plus-plus 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 75636e78a69609289209b2e8faf897cf7ec13233
4
+ data.tar.gz: 887868671b37715daf9e5f3b4a61cc97550485b0
5
+ SHA512:
6
+ metadata.gz: 20b8a936ff4232df2a37776e8b92fa4132f8b5201882beabd0b393310f3c7cedc9fb20e8338342885bb8b07e662f24141b752ccc879452c5cd978c5c61b91d36
7
+ data.tar.gz: 70f2cc035ed493b8ad174f8d3ae6673ed981f0e1db66a0e453a9abdd435fdfbb5693b24b2a3c06eac7e19795d4eb298429217139a82b4304497fb018de01d8ce
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Jamie Davidson
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,125 @@
1
+ # PlusPlus (++)
2
+
3
+ Automatically increment/decrement integer columns with any value obeying any condition. Essentially, a more powerful form of Rails' counter_cache.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+ ```ruby
9
+ gem 'plus-plus'
10
+ ```
11
+
12
+ ## Getting Started
13
+ The simplest use case for ++ is to simply increment/decrement a column keeping track of the count of an association (just like counter_cache):
14
+
15
+ ```ruby
16
+ class Article < ActiveRecord::Base
17
+ has_many :comments
18
+ end
19
+
20
+ class Comment < ActiveRecord::Base
21
+ include PlusPlus
22
+ belongs_to :article
23
+
24
+ plus_plus :article, :comments_count
25
+ end
26
+ ```
27
+
28
+ ```ruby
29
+ article = Article.create! content: "What an article!"
30
+ puts article.comments_count # 0
31
+ comment = Comment.create! content: "You're right, that's one hell of an article!", article: article
32
+ puts article.comments_count # 1
33
+ comment.destroy
34
+ puts article.comments_count # 0
35
+ ```
36
+
37
+ Simple enough! But what if we wanted to ignore a comment based on some condition?
38
+
39
+ ```ruby
40
+ class Comment < ActiveRecord::Base
41
+ include PlusPlus
42
+ belongs_to :article
43
+
44
+ plus_plus :article, :comments_count, unless: proc { fake_comment } # Only increase if the comment is legit. fake_comment can be an instance method, another column, etc.
45
+ end
46
+ ```
47
+
48
+ Well, isn't that swell! But what if the owner of the comment toggles their comment to no longer be fake after it's already been created? Fine, geez!
49
+
50
+ ```ruby
51
+ class Comment < ActiveRecord::Base
52
+ include PlusPlus
53
+ belongs_to :article
54
+
55
+ plus_plus :article, :comments_count, unless: proc { fake_comment } # Only increase if the comment is legit
56
+ plus_plus_on_change :article, :comments_count, changed: :fake_comment, plus: false, minus: true
57
+ ```
58
+
59
+ Ok ok, I see where you're going with this. But hey, I want to work in some gamification and up the user's score when they write articles and comments. Can I do that good sir?
60
+
61
+ ```ruby
62
+ class User < ActiveRecord::Base
63
+ has_many :articles
64
+ has_many :comments
65
+ end
66
+
67
+ class Article < ActiveRecord::Base
68
+ include PlusPlus
69
+ belongs_to :user
70
+ has_many :comments
71
+
72
+ plus_plus :user, :score, value: proc { content.length }
73
+ plus_plus :user, :articles_count, if: proc { published }
74
+ plus_plus_on_change :user, :articles_count, changed: :published, plus: true, minus: false
75
+ end
76
+
77
+ class Comment < ActiveRecord::Base
78
+ include PlusPlus
79
+ belongs_to :user
80
+ belongs_to :article
81
+
82
+ plus_plus :user, :comments_count
83
+ plus_plus :user, :score, value: 5, update_method: :update_attributes, unless: proc { fake_comment }
84
+ plus_plus :article, :comments_count, unless: proc { fake_comment }
85
+ plus_plus_on_change :article, :comments_count, changed: :fake_comment, plus: false, minus: true
86
+ plus_plus_on_change :user, :score, changed: :fake_comment, plus: proc { !fake_comment }, minus: proc { fake_comment }, value: 5, update_method: :update_attributes
87
+ end
88
+ ```
89
+
90
+ ### Options
91
+ Let's bring it all home now:
92
+
93
+ **plus_plus**
94
+ - value: Defaults to 1. Can be set to a static integer value or a proc
95
+ - if: Only update if this condition is satisifed
96
+ - unless: Update unless this condition is satisifed
97
+ - update_method: Defaults to update_columns to avoid triggering callbacks and to be as fast as possible. Set to update_attributes or your own custom method if you prefer callbacks or something different.
98
+
99
+ **plus_plus_on_change**
100
+ - changed: (Required) The column to monitor for a change
101
+ - plus: (Required) The condition that must be satisfied in order to increment the column. Can be a proc (that evaluates to true/false) or a static value that will be checked for equality against the changed column
102
+ - minus: (Required) The condition that must be satisfied in order to decrement the column. Can be a proc (that evaluates to true/false) or a static value that will be checked for equality against the changed column
103
+ - value: Defaults to 1. Can be set to a static integer value or a proc
104
+ - update_method: Defaults to update_columns to avoid triggering callbacks and to be as fast as possible. Set to update_attributes or your own custom method if you prefer callbacks or something different.
105
+
106
+ The MIT License (MIT)
107
+ ---------------------
108
+ Copyright (c) 2014 Pathgather
109
+
110
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
111
+ this software and associated documentation files (the "Software"), to deal in
112
+ the Software without restriction, including without limitation the rights to
113
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
114
+ the Software, and to permit persons to whom the Software is furnished to do so,
115
+ subject to the following conditions:
116
+
117
+ The above copyright notice and this permission notice shall be included in all
118
+ copies or substantial portions of the Software.
119
+
120
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
121
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
122
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
123
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
124
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
125
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,71 @@
1
+ module PlusPlus
2
+ module Base
3
+ def plus_plus(*args)
4
+ options = args.extract_options!
5
+ association, column = args
6
+
7
+ self.after_create {
8
+ self.plus_plus_on_create_or_destroy association, column, options
9
+ }
10
+
11
+ self.after_destroy {
12
+ self.plus_plus_on_create_or_destroy association, column, options
13
+ }
14
+ end
15
+
16
+ def plus_plus_on_change(*args)
17
+ options = args.extract_options!
18
+ association, column = args
19
+
20
+ self.after_update do
21
+ association_model = self.send(association)
22
+ raise "No association #{association}" if association_model.nil?
23
+ raise "No :changed option specified" if options[:changed].nil?
24
+ raise "No :plus option specified" if options[:plus].nil?
25
+ raise "No :minus option specified" if options[:minus].nil?
26
+ return unless self.changes.include?(options[:changed])
27
+
28
+ dup = self.dup
29
+ changed = options[:changed]
30
+ offset = if options[:value]
31
+ options[:value].respond_to?(:call) ? self.instance_exec(&options[:value]) : options[:value]
32
+ else
33
+ 1
34
+ end
35
+
36
+ self.changes.each { |k, v| dup[k] = v.first } # Create a 'snapshot' of what the model did look like
37
+ prev_satisfied_for_minus = options[:minus].respond_to?(:call) ? dup.instance_exec(&options[:minus]) : dup.send(changed) == options[:minus]
38
+ self_satisfied_for_plus = options[:plus].respond_to?(:call) ? self.instance_exec(&options[:plus]) : self.send(changed) == options[:plus]
39
+ self_satisfied_for_minus = options[:minus].respond_to?(:call) ? self.instance_exec(&options[:minus]) : self.send(changed) == options[:minus]
40
+ prev_satisfied_for_plus = options[:plus].respond_to?(:call) ? dup.instance_exec(&options[:plus]) : dup.send(changed) == options[:plus]
41
+
42
+ updated_val = if prev_satisfied_for_minus && self_satisfied_for_plus
43
+ association_model.send(column) + offset
44
+ elsif prev_satisfied_for_plus && self_satisfied_for_minus
45
+ association_model.send(column) - offset
46
+ else
47
+ nil
48
+ end
49
+
50
+ association_model.send options[:update_method] || :update_columns, {column => updated_val} if updated_val
51
+ end
52
+ end
53
+ end
54
+
55
+ module Model
56
+ def plus_plus_on_create_or_destroy(association, column, options)
57
+ association_model = self.send(association)
58
+ raise "No association #{association}" unless association_model
59
+ return if options.has_key?(:if) && !self.instance_exec(&options[:if])
60
+ return if options.has_key?(:unless) && self.instance_exec(&options[:unless])
61
+ value = if options[:value]
62
+ options[:value].respond_to?(:call) ? self.instance_exec(&options[:value]) : options[:value]
63
+ else
64
+ 1
65
+ end
66
+ offset = self.destroyed? ? -(value) : value
67
+ new_val = association_model.send(column) + offset
68
+ association_model.send options[:update_method] || :update_columns, {column => new_val}
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,3 @@
1
+ module PlusPlus
2
+ VERSION = "0.0.1"
3
+ end
data/lib/plus_plus.rb ADDED
@@ -0,0 +1,16 @@
1
+ require "plus_plus/base"
2
+
3
+ module PlusPlus
4
+ def self.extended(model_class)
5
+ return if model_class.respond_to? :plus_plus
6
+ model_class.class_eval do
7
+ extend Base
8
+ include Model
9
+ end
10
+ end
11
+
12
+ # Allow developers to `include` PlusPlus or `extend` it.
13
+ def self.included(model_class)
14
+ model_class.extend self
15
+ end
16
+ end
data/plus_plus.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'plus_plus/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "plus-plus"
8
+ spec.version = PlusPlus::VERSION
9
+ spec.authors = ["Pathgather"]
10
+ spec.email = ["tech@pathgather.com"]
11
+ spec.description = spec.summary = %q{counter_cache, but much more powerful}
12
+ spec.homepage = ""
13
+ spec.license = "MIT"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "rspec-rails", "~> 2.14"
21
+ spec.add_development_dependency "factory_girl", "~> 4.4.0"
22
+ spec.add_development_dependency "bundler", "~> 1.3"
23
+ spec.add_development_dependency "rake"
24
+ spec.add_development_dependency "pry"
25
+ spec.add_development_dependency "activerecord", "~> 4.1.4"
26
+ spec.add_development_dependency "sqlite3"
27
+ end
data/spec/base_spec.rb ADDED
@@ -0,0 +1,177 @@
1
+ require 'spec_helper'
2
+
3
+ describe PlusPlus do
4
+ let(:article) { FactoryGirl.create(:article) }
5
+ let(:article_with_comment) { FactoryGirl.create(:article_with_comment) }
6
+ let(:article_with_subcomment) { FactoryGirl.create(:article_with_subcomment) }
7
+ let(:user) { FactoryGirl.create(:user) }
8
+ let(:user_with_comment) { FactoryGirl.create(:user_with_comment) }
9
+ let(:user_with_published_article) { FactoryGirl.create(:user_with_published_article) }
10
+ let(:user_with_unpublished_article) { FactoryGirl.create(:user_with_unpublished_article) }
11
+
12
+ describe "plus_plus" do
13
+ context "with the minimal configuration" do
14
+ it "increases the column by 1 on create" do
15
+ expect { FactoryGirl.create :comment, user: user }.to change{user.comments_count}.from(0).to(1)
16
+ end
17
+
18
+ it "decreases the column by 1 on destroy" do
19
+ expect { user_with_comment.comments[0].destroy }.to change{user_with_comment.comments_count}.from(1).to(0)
20
+ end
21
+
22
+ it "updates the association with update_columns by default on create" do
23
+ user.should_receive(:update_columns).with({comments_count: 1})
24
+ FactoryGirl.create :comment, user: user
25
+ end
26
+
27
+ it "updates the association with update_columns by default on destroy" do
28
+ user_with_comment.should_receive(:update_columns).with({comments_count: 0})
29
+ user_with_comment.comments[0].destroy
30
+ end
31
+ end
32
+
33
+ context "with a specified value" do
34
+ it "increases the column by that value on create" do
35
+ expect { FactoryGirl.create :comment, user: user }.to change{user.score}.from(0).to(5)
36
+ end
37
+
38
+ it "decreases the column by that value on destroy" do
39
+ expect { user_with_comment.comments[0].destroy }.to change{user_with_comment.score}.from(5).to(0)
40
+ end
41
+ end
42
+
43
+ context "with a dynamic value" do
44
+ it "increases the column by that value on create" do
45
+ expect { FactoryGirl.create :article, user: user, content: 'Test' }.to change{user.score}.from(0).to(4)
46
+ end
47
+
48
+ it "decreases the column by that value on destroy" do
49
+ expect {
50
+ user_with_published_article.articles[0].destroy
51
+ }.to change{user_with_published_article.score}.from(user_with_published_article.articles[0].content.length).to(0)
52
+ end
53
+ end
54
+
55
+ context "with a different update method" do
56
+ it "increases the column with that update method on create" do
57
+ user.should_receive(:update_attributes).with({score: 5})
58
+ FactoryGirl.create :comment, user: user
59
+ end
60
+
61
+ it "decreases the column with that update method on destroy" do
62
+ user_with_comment.should_receive(:update_attributes).with({score: 0})
63
+ user_with_comment.comments[0].destroy
64
+ end
65
+ end
66
+
67
+ context "with an if condition" do
68
+ context "when statisfied" do
69
+ it "increases the column by 1 on create" do
70
+ expect { FactoryGirl.create :published_article, user: user }.to change{user.articles_count}.from(0).to(1)
71
+ end
72
+
73
+ it "decreases the column by 1 on destroy" do
74
+ expect { user_with_published_article.articles[0].destroy }.to change{user_with_published_article.articles_count}.from(1).to(0)
75
+ end
76
+ end
77
+
78
+ context "when not statisfied" do
79
+ it "does not increase the column on create" do
80
+ expect { FactoryGirl.create :article, user: user }.to_not change{user.articles_count}
81
+ end
82
+
83
+ it "does not decrease the column on destroy" do
84
+ expect { user_with_unpublished_article.articles[0].destroy }.to_not change{user_with_unpublished_article.articles_count}
85
+ end
86
+ end
87
+ end
88
+
89
+ context "with an unless condition" do
90
+ context "when statisfied" do
91
+ it "does not increase the column on create" do
92
+ expect { FactoryGirl.create :subcomment, article: article }.to_not change{article.comments_count}
93
+ end
94
+
95
+ it "does not decrease the column on destroy" do
96
+ expect { article_with_subcomment.comments[0].destroy }.to_not change{article_with_subcomment.comments_count}
97
+ end
98
+ end
99
+
100
+ context "when not statisfied" do
101
+ it "increases the column by 1 on create" do
102
+ expect { FactoryGirl.create :comment, article: article }.to change{article.comments_count}.from(0).to(1)
103
+ end
104
+
105
+ it "decreases the column by 1 on destroy" do
106
+ expect { article_with_comment.comments[0].destroy }.to change{article_with_comment.comments_count}.from(1).to(0)
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ describe "plus_plus_on_change" do
113
+ context "with the minimal configuration" do
114
+ context "when the :changed column is changed" do
115
+ it "updates the association with update_columns by default on create" do
116
+ subcomment = FactoryGirl.create :subcomment, article: article
117
+ article.should_receive(:update_columns).with({comments_count: 1})
118
+ subcomment.update_attributes subcomment: false
119
+ end
120
+
121
+ context "when plus is a set value" do
122
+ it "increases the column by 1 if :plus is satisfied" do
123
+ subcomment = FactoryGirl.create :subcomment, article: article
124
+ article.reload
125
+ article.comments_count.should == 0
126
+ subcomment.update_attributes subcomment: false
127
+ article.reload
128
+ article.comments_count.should == 1
129
+ end
130
+ end
131
+
132
+ context "when plus is a proc" do
133
+ it "increases the column by the proc value if :plus is satisfied" do
134
+ subcomment = FactoryGirl.create :subcomment, user: user
135
+ user.reload
136
+ user.score.should == 0
137
+ subcomment.update_attributes subcomment: false
138
+ user.reload
139
+ user.score.should == 5
140
+ end
141
+ end
142
+
143
+ context "when minus is a set valus" do
144
+ it "decreases the column by 1 if :minus is satisfied" do
145
+ article_with_comment.comments_count.should == 1
146
+ article_with_comment.comments[0].update_attributes subcomment: true
147
+ article_with_comment.reload
148
+ article_with_comment.comments_count.should == 0
149
+ end
150
+ end
151
+
152
+ context "when minus is a proc" do
153
+ it "decreases the column by 1 if :minus is satisfied" do
154
+ user_with_comment.score.should == 5
155
+ user_with_comment.comments[0].update_attributes subcomment: true
156
+ user_with_comment.reload
157
+ user_with_comment.score.should == 0
158
+ end
159
+ end
160
+ end
161
+ end
162
+
163
+ context "with a different update method" do
164
+ context "when the :changed column is changed" do
165
+ it "updates the column with that update method" do
166
+ subcomment = FactoryGirl.create :subcomment, user: user
167
+ user.reload
168
+ user.should_receive(:update_attributes).with({score: user.score + 5})
169
+ subcomment.update_attributes subcomment: false
170
+ end
171
+ end
172
+ end
173
+ end
174
+
175
+ it "should raise an error if the association is unknown"
176
+ it "should raise an error if a column is not specified"
177
+ end
data/spec/factories.rb ADDED
@@ -0,0 +1,58 @@
1
+ require 'factory_girl'
2
+
3
+ FactoryGirl.define do
4
+ factory :article do
5
+ content 'Test Article'
6
+ user
7
+ published false
8
+
9
+ factory :published_article do
10
+ published true
11
+ end
12
+
13
+ factory :article_with_comment do
14
+ after(:build) do |article, evaluator|
15
+ article.comments << FactoryGirl.build_list(:comment, 1, article: nil)
16
+ end
17
+ end
18
+
19
+ factory :article_with_subcomment do
20
+ after(:build) do |article, evaluator|
21
+ article.comments << FactoryGirl.build_list(:subcomment, 1, article: nil)
22
+ end
23
+ end
24
+ end
25
+
26
+ factory :comment do
27
+ message 'Test Message'
28
+ user
29
+ article
30
+ subcomment false
31
+
32
+ factory :subcomment do
33
+ subcomment true
34
+ end
35
+ end
36
+
37
+ factory :user do
38
+ name 'Test User'
39
+
40
+ factory :user_with_published_article do
41
+ after(:build) do |user, evaluator|
42
+ user.articles << FactoryGirl.build_list(:published_article, 1, user: nil)
43
+ end
44
+ end
45
+
46
+ factory :user_with_unpublished_article do
47
+ after(:build) do |user, evaluator|
48
+ user.articles << FactoryGirl.build_list(:article, 1, user: nil)
49
+ end
50
+ end
51
+
52
+ factory :user_with_comment do
53
+ after(:build) do |user, evaluator|
54
+ user.comments << FactoryGirl.build_list(:comment, 1, user: nil)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,10 @@
1
+ require 'active_record'
2
+ require 'factories'
3
+ require "pry"
4
+ require 'factory_girl'
5
+ require 'plus_plus'
6
+
7
+ ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
8
+
9
+ load 'support/schema.rb'
10
+ require 'support/models.rb'
@@ -0,0 +1,25 @@
1
+ class User < ActiveRecord::Base
2
+ has_many :articles
3
+ has_many :comments
4
+ end
5
+
6
+ class Article < ActiveRecord::Base
7
+ include PlusPlus
8
+ belongs_to :user
9
+ has_many :comments
10
+
11
+ plus_plus :user, :score, value: proc { content.length }
12
+ plus_plus :user, :articles_count, if: proc { published }
13
+ end
14
+
15
+ class Comment < ActiveRecord::Base
16
+ include PlusPlus
17
+ belongs_to :user
18
+ belongs_to :article
19
+
20
+ plus_plus :user, :comments_count
21
+ plus_plus :user, :score, value: 5, update_method: :update_attributes, unless: proc { subcomment }
22
+ plus_plus :article, :comments_count, unless: proc { subcomment }
23
+ plus_plus_on_change :article, :comments_count, changed: :subcomment, plus: false, minus: true
24
+ plus_plus_on_change :user, :score, changed: :subcomment, plus: proc { !subcomment }, minus: proc { subcomment }, value: 5, update_method: :update_attributes
25
+ end
@@ -0,0 +1,29 @@
1
+ ActiveRecord::Schema.define do
2
+ self.verbose = false
3
+
4
+ create_table :articles, :force => true do |t|
5
+ t.integer :user_id
6
+ t.text :content
7
+ t.boolean :published, default: false
8
+ t.integer :comments_count, default: 0
9
+ t.timestamps
10
+ end
11
+
12
+ create_table :comments, :force => true do |t|
13
+ t.integer :user_id
14
+ t.integer :article_id
15
+ t.text :message
16
+ t.boolean :subcomment, default: false
17
+ t.timestamps
18
+ end
19
+
20
+ create_table :users, :force => true do |t|
21
+ t.string :key
22
+ t.string :name
23
+ t.integer :articles_count, default: 0
24
+ t.integer :comments_count, default: 0
25
+ t.integer :score, default: 0
26
+ t.timestamps
27
+ end
28
+
29
+ end
metadata ADDED
@@ -0,0 +1,161 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: plus-plus
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Pathgather
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-07-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec-rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '2.14'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '2.14'
27
+ - !ruby/object:Gem::Dependency
28
+ name: factory_girl
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 4.4.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 4.4.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: activerecord
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: 4.1.4
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: 4.1.4
97
+ - !ruby/object:Gem::Dependency
98
+ name: sqlite3
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: counter_cache, but much more powerful
112
+ email:
113
+ - tech@pathgather.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - .gitignore
119
+ - Gemfile
120
+ - LICENSE.txt
121
+ - README.md
122
+ - Rakefile
123
+ - lib/plus_plus.rb
124
+ - lib/plus_plus/base.rb
125
+ - lib/plus_plus/version.rb
126
+ - plus_plus.gemspec
127
+ - spec/base_spec.rb
128
+ - spec/factories.rb
129
+ - spec/spec_helper.rb
130
+ - spec/support/models.rb
131
+ - spec/support/schema.rb
132
+ homepage: ''
133
+ licenses:
134
+ - MIT
135
+ metadata: {}
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - '>='
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ requirements: []
151
+ rubyforge_project:
152
+ rubygems_version: 2.1.11
153
+ signing_key:
154
+ specification_version: 4
155
+ summary: counter_cache, but much more powerful
156
+ test_files:
157
+ - spec/base_spec.rb
158
+ - spec/factories.rb
159
+ - spec/spec_helper.rb
160
+ - spec/support/models.rb
161
+ - spec/support/schema.rb