commentable 0.1.0

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,3 @@
1
+ .DS_Store
2
+ pkg
3
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color --format documentation
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://gems.simplesideias.com.br"
2
+ gemspec
@@ -0,0 +1,64 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ commentable (0.1.0)
5
+ activerecord
6
+
7
+ GEM
8
+ remote: http://gems.simplesideias.com.br/
9
+ specs:
10
+ activemodel (3.0.9)
11
+ activesupport (= 3.0.9)
12
+ builder (~> 2.1.2)
13
+ i18n (~> 0.5.0)
14
+ activerecord (3.0.9)
15
+ activemodel (= 3.0.9)
16
+ activesupport (= 3.0.9)
17
+ arel (~> 2.0.10)
18
+ tzinfo (~> 0.3.23)
19
+ activesupport (3.0.9)
20
+ archive-tar-minitar (0.5.2)
21
+ arel (2.0.10)
22
+ builder (2.1.2)
23
+ columnize (0.3.4)
24
+ diff-lcs (1.1.2)
25
+ i18n (0.5.0)
26
+ linecache19 (0.5.12)
27
+ ruby_core_source (>= 0.1.4)
28
+ notifier (0.1.3)
29
+ rake (0.8.7)
30
+ redcarpet (1.17.2)
31
+ rspec (2.6.0)
32
+ rspec-core (~> 2.6.0)
33
+ rspec-expectations (~> 2.6.0)
34
+ rspec-mocks (~> 2.6.0)
35
+ rspec-core (2.6.4)
36
+ rspec-expectations (2.6.0)
37
+ diff-lcs (~> 1.1.2)
38
+ rspec-mocks (2.6.0)
39
+ ruby-debug-base19 (0.11.25)
40
+ columnize (>= 0.3.1)
41
+ linecache19 (>= 0.5.11)
42
+ ruby_core_source (>= 0.1.4)
43
+ ruby-debug19 (0.11.6)
44
+ columnize (>= 0.3.1)
45
+ linecache19 (>= 0.5.11)
46
+ ruby-debug-base19 (>= 0.11.19)
47
+ ruby_core_source (0.1.5)
48
+ archive-tar-minitar (>= 0.5.2)
49
+ sqlite3 (1.3.4)
50
+ test_notifier (0.3.6)
51
+ notifier
52
+ tzinfo (0.3.29)
53
+
54
+ PLATFORMS
55
+ ruby
56
+
57
+ DEPENDENCIES
58
+ commentable!
59
+ rake (~> 0.8.7)
60
+ redcarpet (~> 1.17)
61
+ rspec (~> 2.6)
62
+ ruby-debug19
63
+ sqlite3 (~> 1.3)
64
+ test_notifier (~> 0.3.6)
@@ -0,0 +1,82 @@
1
+ = Commentable
2
+
3
+ This is a really simple ActiveRecord plugin that allows models to be commented.
4
+
5
+ Commentable is tightly coupled to an User model. If you don't have it, there's no game for you here.
6
+
7
+ == Installation
8
+
9
+ gem install commentable
10
+
11
+ == Usage
12
+
13
+ First, you'll have to create the comments table. Run `rails generate migration create_comments` and add the following code:
14
+
15
+ class CreateComments < ActiveRecord::Migration
16
+ def self.up
17
+ create_table :comments do |t|
18
+ t.text :body, :formatted_body
19
+ t.references :commentable, :polymorphic => true
20
+ t.references :user
21
+ t.timestamps
22
+ end
23
+
24
+ add_index :comments, [:commentable_id, :commentable_type], :name => "index_on_commentable"
25
+ add_index :comments, [:commentable_id, :commentable_type, :user_id], :name => "index_on_commentable_and_user"
26
+ end
27
+
28
+ def self.down
29
+ drop_table :comments
30
+ end
31
+ end
32
+
33
+ Run `rake db:migrate` to apply this new migration.
34
+
35
+ Now, add the `commentable` macro to all models that can be commented.
36
+
37
+ class Task < ActiveRecord::Base
38
+ commentable
39
+ end
40
+
41
+ This will create an association called `comments`. You can now create comments like any ActiveRecord model.
42
+
43
+ comment = @task.comments.create(:body => "Awesome job!", :user => @user)
44
+
45
+ There's a shortcut for that.
46
+
47
+ comment = @task.add_comment(:body => "Awesome job!", :user => @user)
48
+
49
+ You can have formatted comments. This is specially useful if you want to provide Markdown support, for instance. Just use the `:format` option passing any variable that responds to the `call` method. The block's return will be used as the `formatted_body` attribute.
50
+
51
+ class Task < ActiveRecord::Base
52
+ commentable :format => proc {|comment| Redcarpet.new(comment.body.to_s).to_html}
53
+ end
54
+
55
+ <b>Final note:</b> remember to add a `comments_count` column to every single model that will be commentable. This is required by the Comment model.
56
+
57
+ == Maintainer
58
+
59
+ * Nando Vieira (http://nandovieira.com.br)
60
+
61
+ == License
62
+
63
+ (The MIT License)
64
+
65
+ Permission is hereby granted, free of charge, to any person obtaining
66
+ a copy of this software and associated documentation files (the
67
+ 'Software'), to deal in the Software without restriction, including
68
+ without limitation the rights to use, copy, modify, merge, publish,
69
+ distribute, sublicense, and/or sell copies of the Software, and to
70
+ permit persons to whom the Software is furnished to do so, subject to
71
+ the following conditions:
72
+
73
+ The above copyright notice and this permission notice shall be
74
+ included in all copies or substantial portions of the Software.
75
+
76
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
77
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
78
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
79
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
80
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
81
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
82
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,5 @@
1
+ require "bundler"
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require "rspec/core/rake_task"
5
+ RSpec::Core::RakeTask.new
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "commentable/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "commentable"
7
+ s.version = Commentable::Version::STRING
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Nando Vieira"]
10
+ s.email = ["fnando.vieira@gmail.com"]
11
+ s.homepage = "http://rubygems.org/gems/commentable"
12
+ s.summary = "Add comment support for ActiveRecord models."
13
+ s.description = s.summary
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_dependency "activerecord"
21
+ s.add_development_dependency "rake", "~> 0.8.7"
22
+ s.add_development_dependency "rspec", "~> 2.6"
23
+ s.add_development_dependency "sqlite3", "~> 1.3"
24
+ s.add_development_dependency "test_notifier", "~> 0.3.6"
25
+ s.add_development_dependency "ruby-debug19"
26
+ s.add_development_dependency "redcarpet", "~> 1.17"
27
+ end
@@ -0,0 +1,22 @@
1
+ require "active_record"
2
+ require "commentable/comment"
3
+ require "commentable/user"
4
+
5
+ module Commentable
6
+ autoload :Version, "commentable/version"
7
+ autoload :InstanceMethods, "commentable/instance_methods"
8
+ autoload :ClassMethods, "commentable/class_methods"
9
+
10
+ def self.extended(base)
11
+ base.class_eval do
12
+ include InstanceMethods
13
+ extend ClassMethods
14
+
15
+ class << self
16
+ attr_accessor :commentable_options
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ ActiveRecord::Base.extend(Commentable)
@@ -0,0 +1,8 @@
1
+ module Commentable
2
+ module ClassMethods
3
+ def commentable(options = {})
4
+ self.commentable_options = options
5
+ has_many :comments, :as => :commentable, :dependent => :destroy
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ class Comment < ActiveRecord::Base
2
+ belongs_to :commentable, :polymorphic => true, :counter_cache => true
3
+ belongs_to :user
4
+
5
+ validates_presence_of :body
6
+ validates_presence_of :user, :commentable
7
+
8
+ before_save :generate_formatted_body
9
+
10
+ private
11
+ def generate_formatted_body
12
+ formatter = commentable.class.commentable_options[:format]
13
+ write_attribute :formatted_body, formatter.call(self) if formatter.respond_to?(:call)
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ module Commentable
2
+ module InstanceMethods
3
+ def add_comment(options = {})
4
+ comments.create(options)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ class User < ActiveRecord::Base
2
+ has_many :comments, :dependent => :nullify
3
+ end
@@ -0,0 +1,8 @@
1
+ module Commentable
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ PATCH = 0
6
+ STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
7
+ end
8
+ end
@@ -0,0 +1,58 @@
1
+ require "spec_helper"
2
+
3
+ describe Comment do
4
+ let(:user) { User.create }
5
+ let(:project) { Project.create }
6
+ let(:task) { Task.create }
7
+ subject { project.add_comment(:body => "Some comment", :user => user) }
8
+
9
+ context "validations" do
10
+ it "requires body" do
11
+ subject.body = nil
12
+ subject.valid?
13
+ subject.errors[:body].should_not be_empty
14
+ end
15
+
16
+ it "requires user" do
17
+ subject.user = nil
18
+ subject.valid?
19
+ subject.errors[:user].should_not be_empty
20
+ end
21
+ end
22
+
23
+ context "associations" do
24
+ its(:user) { should be_an(User) }
25
+ its(:commentable) { should be_a(Project) }
26
+ end
27
+
28
+ context "counter" do
29
+ it "increments counter" do
30
+ expect {
31
+ project.add_comment(:body => "Some comment", :user => user)
32
+ }.to change { project.reload.comments_count }.by(1)
33
+ end
34
+ end
35
+
36
+ context "formatting" do
37
+ it "saves formatted body" do
38
+ subject = task.comments.create(:body => "# Commentable", :user => user)
39
+ subject.formatted_body.should include("<h1>Commentable</h1>")
40
+ end
41
+ end
42
+
43
+ context "removing" do
44
+ let(:user) { User.create }
45
+ let(:task) { Task.create }
46
+ let(:comment) { task.add_comment(:body => "Some comment", :user => user) }
47
+
48
+ it "nullifies existing records when user is removed" do
49
+ user.destroy
50
+ comment.reload.user.should be_nil
51
+ end
52
+
53
+ it "removes existing records when commentable is removed" do
54
+ task.destroy
55
+ Comment.where(:commentable_id => task.id, :commentable_type => task.class.name).count.should be_zero
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,20 @@
1
+ require "spec_helper"
2
+
3
+ describe Commentable do
4
+ let(:user) { User.create }
5
+ let(:project) { Project.create }
6
+
7
+ it "injects association" do
8
+ Project.new.should respond_to(:comments)
9
+ Task.new.should respond_to(:comments)
10
+ end
11
+
12
+ it "skips association" do
13
+ List.new.should_not respond_to(:comments)
14
+ end
15
+
16
+ it "adds new comment shortcut" do
17
+ project.comments.should_receive(:create).with(:body => "Some comment", :user => user)
18
+ project.add_comment(:body => "Some comment", :user => user)
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ create_table :comments do |t|
3
+ t.text :body, :formatted_body
4
+ t.references :commentable, :polymorphic => true
5
+ t.references :user
6
+ t.timestamps
7
+ end
8
+
9
+ add_index :comments, [:commentable_id, :commentable_type], :name => "index_on_commentable"
10
+ add_index :comments, [:commentable_id, :commentable_type, :user_id], :name => "index_on_commentable_and_user"
11
+
12
+ create_table :projects do |t|
13
+ t.integer :comments_count, :null => false, :default => 0
14
+ end
15
+
16
+ create_table :tasks do |t|
17
+ t.integer :comments_count, :null => false, :default => 0
18
+ end
19
+
20
+ create_table :lists do |t|
21
+ t.integer :comments_count, :null => false, :default => 0
22
+ end
23
+
24
+ create_table :users do |t|
25
+ end
26
+ end
@@ -0,0 +1,14 @@
1
+ require "bundler"
2
+ Bundler.setup(:default, :development)
3
+ Bundler.require
4
+
5
+ require "commentable"
6
+ require "test_notifier/runner/rspec"
7
+ require "redcarpet"
8
+
9
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
10
+ load File.dirname(__FILE__) + "/schema.rb"
11
+
12
+ Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each do |file|
13
+ require file
14
+ end
@@ -0,0 +1,10 @@
1
+ class Project < ActiveRecord::Base
2
+ commentable
3
+ end
4
+
5
+ class Task < ActiveRecord::Base
6
+ commentable :format => proc {|comment| Redcarpet.new(comment.body.to_s).to_html}
7
+ end
8
+
9
+ class List < ActiveRecord::Base
10
+ end
metadata ADDED
@@ -0,0 +1,151 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: commentable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Nando Vieira
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-08-01 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: &2156389380 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2156389380
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &2156388840 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 0.8.7
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2156388840
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &2156388300 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: '2.6'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *2156388300
47
+ - !ruby/object:Gem::Dependency
48
+ name: sqlite3
49
+ requirement: &2156387820 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *2156387820
58
+ - !ruby/object:Gem::Dependency
59
+ name: test_notifier
60
+ requirement: &2156387340 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 0.3.6
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *2156387340
69
+ - !ruby/object:Gem::Dependency
70
+ name: ruby-debug19
71
+ requirement: &2156386960 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *2156386960
80
+ - !ruby/object:Gem::Dependency
81
+ name: redcarpet
82
+ requirement: &2156264260 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ~>
86
+ - !ruby/object:Gem::Version
87
+ version: '1.17'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *2156264260
91
+ description: Add comment support for ActiveRecord models.
92
+ email:
93
+ - fnando.vieira@gmail.com
94
+ executables: []
95
+ extensions: []
96
+ extra_rdoc_files: []
97
+ files:
98
+ - .gitignore
99
+ - .rspec
100
+ - Gemfile
101
+ - Gemfile.lock
102
+ - README.rdoc
103
+ - Rakefile
104
+ - commentable.gemspec
105
+ - lib/commentable.rb
106
+ - lib/commentable/class_methods.rb
107
+ - lib/commentable/comment.rb
108
+ - lib/commentable/instance_methods.rb
109
+ - lib/commentable/user.rb
110
+ - lib/commentable/version.rb
111
+ - spec/commentable/comment_spec.rb
112
+ - spec/commentable_spec.rb
113
+ - spec/schema.rb
114
+ - spec/spec_helper.rb
115
+ - spec/support/models.rb
116
+ homepage: http://rubygems.org/gems/commentable
117
+ licenses: []
118
+ post_install_message:
119
+ rdoc_options: []
120
+ require_paths:
121
+ - lib
122
+ required_ruby_version: !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ! '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ segments:
129
+ - 0
130
+ hash: -1833029340048367188
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ none: false
133
+ requirements:
134
+ - - ! '>='
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ segments:
138
+ - 0
139
+ hash: -1833029340048367188
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 1.8.5
143
+ signing_key:
144
+ specification_version: 3
145
+ summary: Add comment support for ActiveRecord models.
146
+ test_files:
147
+ - spec/commentable/comment_spec.rb
148
+ - spec/commentable_spec.rb
149
+ - spec/schema.rb
150
+ - spec/spec_helper.rb
151
+ - spec/support/models.rb