acts_as_caesar 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -6,17 +6,19 @@ h1. Installation
6
6
 
7
7
  Simply add acts_as_caesar to your Gemfile
8
8
 
9
- <pre><code>gem 'acts_as_caesar'</code></pre>
9
+ <pre><code>gem "acts_as_caesar"</code></pre>
10
10
 
11
11
  h2. Requirements
12
12
 
13
13
  You must have Redis server installed. We will seek to make the persistence layer database agnostic over time.
14
14
 
15
+ Candidate objects (things that are being up/downvoted, e.g. comments) must be persisted using ActiveRecord or Mongoid
16
+
15
17
  You must have jQuery installed and JavaScript on the client-side is required.
16
18
 
17
19
  h2. Configuration
18
20
 
19
- Acts As Caesar will connect to Redis on localhost, port 6379 (default for Redis server), unless you override this by creating your own Redis connection using the code below (for Rails place this in @config/initializers/redis.rb@):
21
+ Acts As Caesar expects a Redis connection to exist on the @$redis@ constant, if that's not set it will connect to Redis on localhost, port 6379 (default for Redis server). You can easily create your own Redis connection using the code below (for Rails place this in @config/initializers/redis.rb@):
20
22
 
21
23
  <pre><code>$redis = Redis.new(:host => 'localhost', :port => 6379)</code></pre>
22
24
 
@@ -1,26 +1,41 @@
1
1
  require 'acts_as_caesar/objects/candidate'
2
2
  require 'acts_as_caesar/objects/notification'
3
+ require 'acts_as_caesar/services/active_record_persistence'
4
+ require 'acts_as_caesar/services/mongoid_persistence'
3
5
 
4
6
  module ActsAsCaesar
5
7
  module ActAsCandidate
6
8
  def self.included(base)
7
9
  Notification.subscribe(key: /^#{base.name.downcase.gsub('::', '_')}\_[\da-f]+$/) do |candidate|
8
- candidate.key =~ /\_([\da-f]+)$/ &&
9
- base.find($1).update_total_candidate_score
10
+ handle_candidate_update_notification(base, candidate)
10
11
  end
11
12
  end
12
13
 
13
- def as_candidate
14
- @as_candidate = ActsAsCaesar::Candidate.new(self)
15
- end
16
-
17
- def update_total_candidate_score
18
- self.score = total_candidate_score
19
- save!
14
+ def self.handle_candidate_update_notification(base, candidate)
15
+ # ensure we have an id
16
+ unless candidate.key =~ /\_([\da-f]+)$/ && id = $1
17
+ raise ArgumentError, "#{candidate.key} does not contain a valid key"
18
+ end
19
+
20
+ if ActiveRecordPersistence.can_handle?(base)
21
+ ActiveRecordPersistence.new(base, id).update_score
22
+ elsif MongoidPersistence.can_handle?(base)
23
+ MongoidPersistence.new(base, id).update_score
24
+ elsif base.respond_to?(:acts_as_caesar_score_persistence)
25
+ base.acts_as_caesar_score_persistence.new(base, id).update_score
26
+ else
27
+ raise StandardError, %Q(
28
+ Incompatible database adapter, try implementing the following method:
29
+ def self.acts_as_caesar_score_persistence
30
+ # returns a class name like lib/acts_as_caesar/services/mongoid_persistence.rb
31
+ # e.g. MongoidPersistence
32
+ end
33
+ )
34
+ end
20
35
  end
21
36
 
22
37
  def total_candidate_score
23
- @total_candidate_score ||= as_candidate.total
38
+ ActsAsCaesar::Candidate.new(self).total
24
39
  end
25
40
  end
26
41
  end
@@ -0,0 +1,23 @@
1
+ module ActsAsCaesar
2
+ class ActiveRecordPersistence
3
+ class << self
4
+ def can_handle?(klass)
5
+ defined?(ActiveRecord) && defined?(ActiveRecord::Base) &&
6
+ (klass < ActiveRecord::Base)
7
+ end
8
+ end
9
+
10
+ def initialize(klass, id)
11
+ @klass = klass
12
+ @id = id
13
+ end
14
+
15
+ def update_score
16
+ candidate.update_attribute(:score, candidate.total_candidate_score)
17
+ end
18
+
19
+ def candidate
20
+ @candidate ||= @klass.find(@id)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,52 @@
1
+ module ActsAsCaesar
2
+ class MongoidPersistence
3
+ class << self
4
+ def can_handle?(klass)
5
+ defined?(Mongoid) && defined?(Mongoid::Document) &&
6
+ klass.included_modules.include?(Mongoid::Document)
7
+ end
8
+ end
9
+
10
+ def initialize(klass, id)
11
+ @klass = klass
12
+ @id = id
13
+ end
14
+
15
+ def update_score
16
+ puts "Updating score of #{candidate}"
17
+ candidate.update_attribute(:score, candidate.total_candidate_score)
18
+ end
19
+
20
+ def candidate
21
+ return @candidate if defined?(@candidate)
22
+
23
+ relations = []
24
+ klass = @klass
25
+
26
+ # loop back through nesting, appending relations
27
+ while (embedded_relations = klass.relations.select { |k,v| v.macro == :embedded_in }) && embedded_relations.size > 0
28
+ relation = embedded_relations.values.first
29
+ klass = relation.class_name.constantize
30
+ relations << relation.inverse_of
31
+ end
32
+
33
+ # start at the root document
34
+ scope = klass
35
+
36
+ # for each nested relation
37
+ while relation = relations.pop
38
+ key = relation.to_s
39
+ if relations.size > 0
40
+ key += "."
41
+ key += relations.reverse.join(".")
42
+ end
43
+ key += "._id"
44
+ # append the condition
45
+ scope = scope.where(key => BSON::ObjectId(@id)).first.send(relation)
46
+ end
47
+
48
+ # find the final object
49
+ @candidate = scope.find(@id)
50
+ end
51
+ end
52
+ end
@@ -1,3 +1,3 @@
1
1
  module ActsAsCaesar
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -1,9 +1,44 @@
1
- require_relative '../../lib/acts_as_caesar/modules/act_as_candidate'
2
- require_relative '../../lib/acts_as_caesar/objects/notification'
1
+ require "mongoid"
2
+ require_relative "../../lib/acts_as_caesar/modules/act_as_candidate"
3
+ require_relative "../../lib/acts_as_caesar/objects/notification"
3
4
 
4
5
  class ActsAsCaesar::TestActAsCandidate
5
6
  attr_accessor :score
6
7
  include ActsAsCaesar::ActAsCandidate
8
+
9
+ def key
10
+ "#{self.class.name}_abcdef1234567890"
11
+ end
12
+ end
13
+
14
+ class ActsAsCaesar::MongoTestActAsCandidate
15
+ include Mongoid::Document
16
+ include ActsAsCaesar::ActAsCandidate
17
+
18
+ field :score, type: Integer
19
+
20
+ embeds_many :nested_mongo_tests,
21
+ class_name: "ActsAsCaesar::NestedMongoTestActAsCandidate",
22
+ inverse_of: :mongo_test
23
+
24
+ def key
25
+ "#{self.class.name}_#{id}"
26
+ end
27
+ end
28
+
29
+ class ActsAsCaesar::NestedMongoTestActAsCandidate
30
+ include Mongoid::Document
31
+ include ActsAsCaesar::ActAsCandidate
32
+
33
+ field :score, type: Integer
34
+
35
+ embedded_in :mongo_test,
36
+ class_name: "ActsAsCaesar::MongoTestActAsCandidate",
37
+ inverse_of: :nested_mongo_tests
38
+
39
+ def key
40
+ "#{self.class.name}_#{id}"
41
+ end
7
42
  end
8
43
 
9
44
  describe ActsAsCaesar::ActAsCandidate do
@@ -26,18 +61,68 @@ describe ActsAsCaesar::ActAsCandidate do
26
61
  end
27
62
 
28
63
  context "when updating the score" do
29
- before(:each) do
30
- subject.should_receive(:total_candidate_score).and_return(987)
31
- subject.should_receive(:save!).and_return(true)
64
+ context "of an ActiveRecord object" do
65
+ before(:each) do
66
+ ActsAsCaesar::ActiveRecordPersistence.should_receive(:can_handle?).and_return(true)
67
+ ActsAsCaesar::ActiveRecordPersistence.any_instance.should_receive(:candidate).any_number_of_times.and_return(subject)
68
+ subject.should_receive(:total_candidate_score).and_return(987)
69
+ subject.should_receive(:update_attribute).with(:score, 987).and_return(true)
70
+ end
71
+
72
+ it "should persist the score" do
73
+ ActsAsCaesar::ActAsCandidate.handle_candidate_update_notification(subject.class, subject)
74
+ end
32
75
  end
33
76
 
34
- it "should set the score to the total candidate score" do
35
- subject.update_total_candidate_score
36
- subject.score.should == 987
77
+ context "of a Mongoid object" do
78
+ before(:each) do
79
+ ActsAsCaesar::MongoidPersistence.should_receive(:can_handle?).and_return(true)
80
+ ActsAsCaesar::MongoidPersistence.any_instance.should_receive(:candidate).any_number_of_times.and_return(subject)
81
+ subject.should_receive(:total_candidate_score).and_return(987)
82
+ subject.should_receive(:update_attribute).with(:score, 987).and_return(true)
83
+ end
84
+
85
+ it "should persist the score" do
86
+ ActsAsCaesar::ActAsCandidate.handle_candidate_update_notification(subject.class, subject)
87
+ end
37
88
  end
89
+
90
+ context "of a nested Mongoid object" do
91
+ subject do
92
+ parent = ActsAsCaesar::MongoTestActAsCandidate.create!
93
+ parent.nested_mongo_tests.create!
94
+ end
38
95
 
39
- it "should return true" do
40
- subject.update_total_candidate_score.should == true
96
+ before(:each) do
97
+ ActsAsCaesar::NestedMongoTestActAsCandidate.any_instance.should_receive(:total_candidate_score).and_return(987)
98
+ ActsAsCaesar::NestedMongoTestActAsCandidate.any_instance.should_receive(:update_attribute).once.with(:score, 987).and_return(true)
99
+ end
100
+
101
+ it "should persist the score" do
102
+ ActsAsCaesar::ActAsCandidate.handle_candidate_update_notification(subject.class, subject)
103
+ end
104
+ end
105
+
106
+ context "of an object with custom AAC support" do
107
+ class CustomPersister < Struct.new(:klass, :id); end
108
+
109
+ before(:each) do
110
+ subject.class.should_receive(:respond_to?).with(:acts_as_caesar_score_persistence).and_return(true)
111
+ subject.class.should_receive(:acts_as_caesar_score_persistence).and_return(CustomPersister)
112
+ CustomPersister.any_instance.should_receive(:update_score).and_return(true)
113
+ end
114
+
115
+ it "should call the custom class" do
116
+ ActsAsCaesar::ActAsCandidate.handle_candidate_update_notification(subject.class, subject).should be_true
117
+ end
118
+ end
119
+
120
+ context "of an object without custom AAC support" do
121
+ it "should raise an error" do
122
+ lambda do
123
+ ActsAsCaesar::ActAsCandidate.handle_candidate_update_notification(subject.class, subject)
124
+ end.should raise_error
125
+ end
41
126
  end
42
127
  end
43
128
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_caesar
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
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: 2012-04-24 00:00:00.000000000 Z
12
+ date: 2012-06-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: redis
@@ -244,6 +244,8 @@ files:
244
244
  - lib/acts_as_caesar/rack.rb
245
245
  - lib/acts_as_caesar/rails/engine.rb
246
246
  - lib/acts_as_caesar/rails/view_helpers.rb
247
+ - lib/acts_as_caesar/services/active_record_persistence.rb
248
+ - lib/acts_as_caesar/services/mongoid_persistence.rb
247
249
  - lib/acts_as_caesar/version.rb
248
250
  - spec/assets/jasmine_helper.js.coffee
249
251
  - spec/assets/jquery_helper.js.coffee