parole 0.0.1 → 0.1

Sign up to get free protection for your applications and to get access to all the features.
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