parole 0.0.1 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bcabaf06d28e44a6f2bdb705ff7cee1dec0dabc8
4
- data.tar.gz: 1aa7738d85f9a1eca9e25c205d957c8a85390267
3
+ metadata.gz: 4ee674fa482c0e5bdac4920a45ebe3cf3b432d6e
4
+ data.tar.gz: 9ced8509fb977a20a4ae990dff8b6e508a65f489
5
5
  SHA512:
6
- metadata.gz: 293a9952bb46794c66fd545adf8f9dc0b82c4b322d599e4ecc4ffb36119a8d3a4b4253fd5fd705b7fcd96f19c5204c00cb46be39e1bc9fbe3b37924cbb143e71
7
- data.tar.gz: a3e07a743dc843ce00b475dd6e21b690f40ef2f342826aa9a3b563340e4ace9491edd048baa843357b743feeb5dd8c3e49baf29da1a7d1f259bf9ad9287acd21
6
+ metadata.gz: 8cbfe7a1ccfc90c130c331d195b545eb55b5bfb791c5b0d18d89c0253b180f082569abe3f7ca417d14c35a188a51e41b87cff0693ddc25e320b695e4e9ece3a5
7
+ data.tar.gz: 3ed9ae68d461e3f721023eee4030ad167c46c037880d31f7677f502a9c772c158b58fd20c4329ae2e2e76d2aa268adffb0fbc3792550b8ea5b8606e09c99e235
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # Parole
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/parole.png)](https://rubygems.org/gems/parole)
4
+
5
+ Parole adds the ability to comment on ActiveRecord records.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'parole'
13
+ ```
14
+
15
+ Then run the task to generate the migration:
16
+
17
+ ```bash
18
+ $ rails generate parole:install
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ You should now be able to mark models as *commentable*:
24
+
25
+ ```ruby
26
+ class Article < ActiveRecord::Base
27
+ acts_as_commentable
28
+ end
29
+ ```
30
+
31
+ You’re pretty much done after that. You’re now able to do this:
32
+
33
+ ```ruby
34
+ user = User.find(1)
35
+ article = Article.find(1)
36
+
37
+ article.comments.create(commenter: user, comment: 'Hello world!')
38
+ article.comments.count # => 1
39
+ ```
40
+
41
+ You can also provide roles for comments, so you can have multiple type of comments per record.
42
+
43
+ ```ruby
44
+ class Article < ActiveRecord::Base
45
+ acts_as_commentable roles: [:photos, :videos]
46
+ end
47
+
48
+ user = User.find(1)
49
+ article = Article.find(1)
50
+
51
+ article.photos_comments.create(commenter: user, comment: 'Hello world!')
52
+ article.photos_comments.count # => 1
53
+ article.comments.count # => 1
54
+ ```
55
+
56
+ ### Cache counters
57
+
58
+ Whenever a comment is created or destroyed, Parole looks into the commentable record and check
59
+ if there’s a `<role>_comments_count` column and/or a `comments_count` column. If so, it updates
60
+ them so they reflect the total number of comments and the number of comments of this role for
61
+ the record.
62
+
63
+ So let’s say the `Article` model has the following columns: `photos_comments_count`, `videos_comments_count` and `comments_count`.
64
+
65
+ ```ruby
66
+ class Article < ActiveRecord::Base
67
+ acts_as_commentable roles: [:photos, :videos]
68
+ end
69
+
70
+ user = User.find(1)
71
+ article = Article.find(1)
72
+
73
+ article.photos_comments.create(commenter: user, comment: 'Hello world!')
74
+ article.photos_comments_count # => 1
75
+ article.videos_comments_count # => 0
76
+ article.comments_count # => 1
77
+
78
+ article.videos_comments.create(commenter: user, comment: 'Hello world again!')
79
+ article.photos_comments_count # => 1
80
+ article.videos_comments_count # => 1
81
+ article.comments_count # => 2
82
+ ```
83
+
84
+ ## License
85
+
86
+ `Parole` is © 2013 [Mirego](http://www.mirego.com) and may be freely distributed under the [New BSD license](http://opensource.org/licenses/BSD-3-Clause). See the [`LICENSE.md`](https://github.com/mirego/parole/blob/master/LICENSE.md) file.
87
+
88
+ ## About Mirego
89
+
90
+ Mirego is a team of passionate people who believe that work is a place where you can innovate and have fun. We proudly build mobile applications for [iPhone](http://mirego.com/en/iphone-app-development/ "iPhone application development"), [iPad](http://mirego.com/en/ipad-app-development/ "iPad application development"), [Android](http://mirego.com/en/android-app-development/ "Android application development"), [Blackberry](http://mirego.com/en/blackberry-app-development/ "Blackberry application development"), [Windows Phone](http://mirego.com/en/windows-phone-app-development/ "Windows Phone application development") and [Windows 8](http://mirego.com/en/windows-8-app-development/ "Windows 8 application development") in beautiful Quebec City.
91
+
92
+ We also love [open-source software](http://open.mirego.com/) and we try to extract as much code as possible from our projects to give back to the community.
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
@@ -0,0 +1,6 @@
1
+ Description:
2
+ Copies comment.rb to app/models/.
3
+ Copies create_comment.rb to db/migrate
4
+
5
+ Examples:
6
+ `rails generate comment`
@@ -0,0 +1,29 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ module Parole
5
+ module Generators
6
+ class InstallGenerator < Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+ source_root File.expand_path('../templates', __FILE__)
9
+
10
+ # Implement the required interface for Rails::Generators::Migration.
11
+ # taken from http://github.com/rails/rails/blob/master/activerecord/lib/generators/active_record.rb
12
+ def self.next_migration_number(dirname)
13
+ if ActiveRecord::Base.timestamped_migrations
14
+ Time.now.utc.strftime('%Y%m%d%H%M%S')
15
+ else
16
+ '%.3d' % (current_migration_number(dirname) + 1)
17
+ end
18
+ end
19
+
20
+ def create_migration_file
21
+ migration_template 'migration.rb', 'db/migrate/add_parole.rb'
22
+ end
23
+
24
+ def create_model_file
25
+ template "model.rb", "app/models/comment.rb"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,18 @@
1
+ class AddParole < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :comments do |t|
4
+ t.references :commentable, polymorphic: true
5
+ t.references :commenter, polymorphic: true
6
+ t.string :role, default: 'comment'
7
+ t.text :comment
8
+
9
+ t.timestamps
10
+ end
11
+
12
+ add_index :comments, [:commentable_type, :commentable_id, :role]
13
+ end
14
+
15
+ def self.down
16
+ drop_table :comments
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ class Comment < ActiveRecord::Base
2
+ acts_as_comment
3
+ end
@@ -0,0 +1,53 @@
1
+ module Parole
2
+ module Comment
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ # Associations
7
+ belongs_to :commentable, polymorphic: true
8
+ belongs_to :commenter, polymorphic: true
9
+
10
+ # Callbacks
11
+ after_create :update_cache_counters
12
+ after_destroy :update_cache_counters
13
+
14
+ # Validations
15
+ validate :ensure_valid_role_for_commentable
16
+ validate :ensure_valid_commentable
17
+ validate :commenter, presence: true
18
+ validate :commentable, presence: true
19
+ validate :comment, presence: true
20
+ end
21
+
22
+ protected
23
+
24
+ def update_cache_counters
25
+ role_method = :"#{self.role}_comments_count="
26
+ if commentable.respond_to?(role_method)
27
+ commentable.send role_method, commentable.comments.where(role: self.role).count
28
+ end
29
+
30
+ total_method = :comments_count=
31
+ if commentable.respond_to?(total_method)
32
+ commentable.send total_method, commentable.comments.count
33
+ end
34
+
35
+ commentable.save(validate: false)
36
+ end
37
+
38
+ def ensure_valid_role_for_commentable
39
+ allowed_roles = commentable.class.commentable_options[:roles]
40
+
41
+ if allowed_roles.any?
42
+ errors.add(:role, :invalid) unless allowed_roles.include?(self.role)
43
+ else
44
+ errors.add(:role, :invalid) unless self.role.blank?
45
+ end
46
+ end
47
+
48
+ def ensure_valid_commentable
49
+ klass = commentable.class
50
+ errors.add(:commentable, :invalid) unless klass.respond_to?(:acts_as_commentable?) && klass.acts_as_commentable?
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,19 @@
1
+ module Parole
2
+ module Commentable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ # Default options for all comments associations
7
+ association_options = { class_name: 'Comment', as: :commentable, dependent: :destroy }
8
+
9
+ # All comments for the record
10
+ has_many :comments, association_options
11
+
12
+ # Role-specific comments for the record
13
+ commentable_options.fetch(:roles).each do |role|
14
+ options = association_options.merge before_add: lambda { |_, comment| comment.role = role }
15
+ has_many :"#{role}_comments", lambda { where(role: role) }, options
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,3 +1,3 @@
1
1
  module Parole
2
- VERSION = '0.0.1'
2
+ VERSION = '0.1'
3
3
  end
data/lib/parole.rb CHANGED
@@ -1,4 +1,26 @@
1
1
  require 'parole/version'
2
2
 
3
- module Parole
3
+ require 'active_record'
4
+ require 'active_support'
5
+
6
+ require 'parole/commentable'
7
+ require 'parole/comment'
8
+
9
+ class ActiveRecord::Base
10
+ def self.acts_as_commentable(options = {})
11
+ class_attribute :commentable_options, :acts_as_commentable
12
+ self.acts_as_commentable = true
13
+ self.commentable_options = options.reverse_merge(roles: [])
14
+ self.commentable_options[:roles] = commentable_options[:roles].map(&:to_s)
15
+
16
+ include Parole::Commentable
17
+ end
18
+
19
+ def self.acts_as_commentable?
20
+ !!self.acts_as_commentable
21
+ end
22
+
23
+ def self.acts_as_comment(*args)
24
+ include Parole::Comment
25
+ end
4
26
  end
data/parole.gemspec CHANGED
@@ -8,9 +8,9 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Parole::VERSION
9
9
  spec.authors = ['Rémi Prévost']
10
10
  spec.email = ['rprevost@mirego.com']
11
- spec.description = ''
12
- spec.summary = ''
13
- spec.homepage = ''
11
+ spec.description = 'Parole adds the ability to comment on ActiveRecord models.'
12
+ spec.summary = spec.description
13
+ spec.homepage = 'http://open.mirego.com/parole'
14
14
  spec.license = 'BSD 3-Clause'
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
@@ -20,4 +20,9 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency 'bundler'
22
22
  spec.add_development_dependency 'rake'
23
+ spec.add_development_dependency 'sqlite3'
24
+ spec.add_development_dependency 'rspec', '~> 2.14'
25
+
26
+ spec.add_dependency 'activerecord', '>= 4.0.0'
27
+ spec.add_dependency 'activesupport', '>= 4.0.0'
23
28
  end
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ describe Parole::Comment do
4
+ end
@@ -0,0 +1,107 @@
1
+ require 'spec_helper'
2
+
3
+ describe Parole::Commentable do
4
+ describe :comments do
5
+ before do
6
+ spawn_comment_model
7
+ spawn_commenter_model 'User'
8
+ spawn_commentable_model 'Article'
9
+
10
+ run_migration do
11
+ create_table(:articles, force: true)
12
+ create_table(:users, force: true)
13
+ end
14
+ end
15
+
16
+ let(:commenter) { User.create }
17
+ let(:commentable) { Article.create }
18
+
19
+ context 'without role attribute' do
20
+ let(:comment) { commentable.comments.create(commenter: commenter, comment: 'Booya') }
21
+
22
+ it { expect(comment).to be_persisted }
23
+ it { expect(comment.comment).to eql 'Booya' }
24
+ it { expect(comment.commenter).to eql commenter }
25
+ it { expect(comment.commentable).to eql commentable }
26
+ end
27
+
28
+ context 'with role attribute' do
29
+ let(:comment) { commentable.comments.create(role: 'YEP', commenter: commenter, comment: 'Booya') }
30
+ it { expect(comment).to_not be_persisted }
31
+ it { expect(comment.errors.full_messages).to eql ['Role is invalid'] }
32
+ end
33
+ end
34
+
35
+ describe 'role comments' do
36
+ before do
37
+ spawn_comment_model
38
+ spawn_commenter_model 'User'
39
+ spawn_commentable_model 'Article' do
40
+ acts_as_commentable roles: [:photos, :videos]
41
+ end
42
+
43
+ run_migration do
44
+ create_table(:articles, force: true)
45
+ create_table(:users, force: true)
46
+ end
47
+ end
48
+
49
+ let(:commenter) { User.create }
50
+ let(:commentable) { Article.create }
51
+
52
+ context 'with commentable role association method' do
53
+ let(:comment) { commentable.photos_comments.create(commenter: commenter, comment: 'Booya') }
54
+
55
+ it { expect(comment).to be_persisted }
56
+ it { expect(comment.role).to eql 'photos' }
57
+ it { expect(comment.comment).to eql 'Booya' }
58
+ it { expect(comment.commenter).to eql commenter }
59
+ it { expect(comment.commentable).to eql commentable }
60
+ end
61
+
62
+ context 'with commentable main association method' do
63
+ context 'with valid role' do
64
+ let(:comment) { commentable.comments.create(role: 'photos', commenter: commenter, comment: 'Booya') }
65
+
66
+ it { expect(comment).to be_persisted }
67
+ it { expect(comment.role).to eql 'photos' }
68
+ it { expect(comment.comment).to eql 'Booya' }
69
+ it { expect(comment.commenter).to eql commenter }
70
+ it { expect(comment.commentable).to eql commentable }
71
+ end
72
+
73
+ context 'with invalid role' do
74
+ let(:comment) { commentable.comments.create(role: 'NOPE', commenter: commenter, comment: 'Booya') }
75
+ it { expect(comment).to_not be_persisted }
76
+ it { expect(comment.errors.full_messages).to eql ['Role is invalid'] }
77
+ end
78
+ end
79
+ end
80
+
81
+ describe 'cache counters' do
82
+ before do
83
+ spawn_comment_model
84
+ spawn_commenter_model 'User'
85
+ spawn_commentable_model 'Article' do
86
+ acts_as_commentable roles: [:photos, :videos]
87
+ end
88
+
89
+ run_migration do
90
+ create_table(:users, force: true)
91
+ create_table(:articles, force: true) do |t|
92
+ t.integer :photos_comments_count, default: 0
93
+ t.integer :videos_comments_count, default: 0
94
+ t.integer :comments_count, default: 0
95
+ end
96
+ end
97
+ end
98
+
99
+ let(:commenter) { User.create }
100
+ let(:commentable) { Article.create }
101
+ let(:create_comment!) { commentable.photos_comments.create(commenter: commenter, comment: 'Booya') }
102
+
103
+ it { expect { create_comment! }.to change { commentable.reload.photos_comments_count }.from(0).to(1) }
104
+ it { expect { create_comment! }.to_not change { commentable.reload.videos_comments_count } }
105
+ it { expect { create_comment! }.to change { commentable.reload.comments_count }.from(0).to(1) }
106
+ end
107
+ end
@@ -0,0 +1,31 @@
1
+ $:.unshift File.expand_path('../lib', __FILE__)
2
+
3
+ require 'rspec'
4
+ require 'sqlite3'
5
+
6
+ require 'parole'
7
+
8
+ # Require our macros and extensions
9
+ Dir[File.expand_path('../../spec/support/macros/*.rb', __FILE__)].map(&method(:require))
10
+
11
+ RSpec.configure do |config|
12
+ # Include our macros
13
+ config.include DatabaseMacros
14
+ config.include ModelMacros
15
+
16
+ config.before(:each) do
17
+ # Create the SQLite database
18
+ setup_database
19
+
20
+ # Run our migration
21
+ run_default_migration
22
+ end
23
+
24
+ config.after(:each) do
25
+ # Make sure we remove our test database file
26
+ cleanup_database
27
+
28
+ # Remove our models
29
+ flush_models!
30
+ end
31
+ 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/parole/templates/migration.rb', __FILE__)
37
+ AddParole.new.up
38
+ end
39
+ end
@@ -0,0 +1,39 @@
1
+ module ModelMacros
2
+ # Create a new commentable model
3
+ def spawn_commentable_model(klass_name = 'Article', &block)
4
+ spawn_model klass_name, ActiveRecord::Base do
5
+ acts_as_commentable unless block
6
+ instance_exec(&block) if block
7
+ end
8
+ end
9
+
10
+ # Create a new comment model
11
+ def spawn_comment_model(klass_name = 'Comment', &block)
12
+ spawn_model klass_name, ActiveRecord::Base do
13
+ acts_as_comment unless block
14
+ instance_exec(&block) if block
15
+ end
16
+ end
17
+
18
+ # Create a new commenter model
19
+ def spawn_commenter_model(klass_name = 'User', &block)
20
+ spawn_model klass_name, ActiveRecord::Base do
21
+ has_many :comments unless block
22
+ instance_exec(&block) if block
23
+ end
24
+ end
25
+
26
+ protected
27
+
28
+ # Create a new model class
29
+ def spawn_model(klass_name, parent_klass, &block)
30
+ @spawned_models ||= []
31
+ Object.instance_eval { remove_const klass_name } if Object.const_defined?(klass_name)
32
+ @spawned_models << Object.const_set(klass_name, Class.new(parent_klass))
33
+ Object.const_get(klass_name).class_eval(&block) if block_given?
34
+ end
35
+
36
+ def flush_models!
37
+ @spawned_models.each { |model| Object.instance_eval { remove_const model.name.to_sym } }
38
+ end
39
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parole
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: '0.1'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rémi Prévost
@@ -38,7 +38,63 @@ dependencies:
38
38
  - - '>='
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
- description: ''
41
+ - !ruby/object:Gem::Dependency
42
+ name: sqlite3
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.14'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '2.14'
69
+ - !ruby/object:Gem::Dependency
70
+ name: activerecord
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: 4.0.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: 4.0.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: activesupport
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: 4.0.0
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: 4.0.0
97
+ description: Parole adds the ability to comment on ActiveRecord models.
42
98
  email:
43
99
  - rprevost@mirego.com
44
100
  executables: []
@@ -46,12 +102,25 @@ extensions: []
46
102
  extra_rdoc_files: []
47
103
  files:
48
104
  - .gitignore
105
+ - .rspec
49
106
  - Gemfile
107
+ - README.md
50
108
  - Rakefile
109
+ - lib/generators/parole/USAGE
110
+ - lib/generators/parole/install_generator.rb
111
+ - lib/generators/parole/templates/migration.rb
112
+ - lib/generators/parole/templates/model.rb
51
113
  - lib/parole.rb
114
+ - lib/parole/comment.rb
115
+ - lib/parole/commentable.rb
52
116
  - lib/parole/version.rb
53
117
  - parole.gemspec
54
- homepage: ''
118
+ - spec/parole/comment_spec.rb
119
+ - spec/parole/commentable_spec.rb
120
+ - spec/spec_helper.rb
121
+ - spec/support/macros/database_macros.rb
122
+ - spec/support/macros/model_macros.rb
123
+ homepage: http://open.mirego.com/parole
55
124
  licenses:
56
125
  - BSD 3-Clause
57
126
  metadata: {}
@@ -74,5 +143,10 @@ rubyforge_project:
74
143
  rubygems_version: 2.1.0
75
144
  signing_key:
76
145
  specification_version: 4
77
- summary: ''
78
- test_files: []
146
+ summary: Parole adds the ability to comment on ActiveRecord models.
147
+ test_files:
148
+ - spec/parole/comment_spec.rb
149
+ - spec/parole/commentable_spec.rb
150
+ - spec/spec_helper.rb
151
+ - spec/support/macros/database_macros.rb
152
+ - spec/support/macros/model_macros.rb