mongoid-publishable 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.
@@ -0,0 +1,51 @@
1
+ require "mongoid/publishable/unpublished_object"
2
+
3
+ module Mongoid
4
+ module Publishable
5
+ class Queue < Array
6
+
7
+ # loads the queue from the session
8
+ def self.load(session = nil)
9
+ # create a new queue
10
+ queue = new
11
+ # if there was no existing queue, return new
12
+ return queue unless session
13
+ # create our contents
14
+ contents = session.split("\n").map do |data|
15
+ UnpublishedObject.deserialize_from_session(data)
16
+ end
17
+ # add into the queue
18
+ queue.replace(contents)
19
+ end
20
+
21
+ # publishes all the objects on the queue to this user
22
+ def publish_via(publisher)
23
+ remaining = delete_if do |model|
24
+ model.publish_via!(publisher)
25
+ model.published?
26
+ end
27
+ # replaces the contents with the remaining models
28
+ replace(remaining)
29
+ end
30
+
31
+ # creates a string containing the data of the queue
32
+ def dump
33
+ map do |model|
34
+ model.serialize_for_session
35
+ end.join("\n")
36
+ end
37
+
38
+ # adds a new object to the queue
39
+ def push(*models)
40
+ # map each item to an unpublished object
41
+ models = Array(models).map do |model|
42
+ UnpublishedObject.new(model: model)
43
+ end
44
+ # add them to the array
45
+ super(*models)
46
+ end
47
+ alias_method :<<, :push
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,27 @@
1
+ require "mongoid/publishable/queue"
2
+
3
+ module Mongoid
4
+ module Publishable
5
+ module Queuing
6
+ def self.included(base)
7
+ base.class_eval do
8
+ before_filter :deserialize_publishing_queue
9
+ after_filter :serialize_publishing_queue
10
+ attr_reader :publishing_queue
11
+ end
12
+ base.send(:include, InstanceMethods)
13
+ end
14
+
15
+ module InstanceMethods
16
+ protected
17
+ def deserialize_publishing_queue
18
+ @publishing_queue = Queue.load(session[:publishing_queue])
19
+ end
20
+
21
+ def serialize_publishing_queue
22
+ session[:publishing_queue] = @publishing_queue.dump
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,7 @@
1
+ module Mongoid
2
+ module Publishable
3
+ class UnpublishedError < StandardError
4
+ attr_accessor :model
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,88 @@
1
+ require "multi_json"
2
+
3
+ module Mongoid
4
+ module Publishable
5
+ class UnpublishedObject
6
+ def self.deserialize_from_session(data)
7
+ new(data: data)
8
+ end
9
+
10
+ def initialize(options = {})
11
+ if options[:model]
12
+ @source_object = options[:model]
13
+ elsif options[:data]
14
+ @serialized_data = options[:data]
15
+ else
16
+ raise ArgumentError, "No :model or :data provided"
17
+ end
18
+ end
19
+
20
+ def serialize_for_session
21
+ @serialized_data ||= serialize_object_for_session
22
+ end
23
+
24
+ def params
25
+ MultiJson.load(@serialized_data)
26
+ end
27
+
28
+ def respond_to_missing?(method)
29
+ source_object.respond_to?(method)
30
+ end
31
+
32
+ def method_missing(method, *args, &block)
33
+ if respond_to_missing?(method)
34
+ source_object.send(method, *args, &block)
35
+ else
36
+ super
37
+ end
38
+ end
39
+
40
+ def source_object
41
+ @source_object ||= load_source_object_from_params
42
+ end
43
+
44
+ private
45
+ def load_source_object_from_params
46
+ data = params
47
+ # load the top level object
48
+ object = data["class_name"].constantize.find(data["id"])
49
+ # if we have embedded stuff
50
+ while data["embedded"]
51
+ # work on the next level down
52
+ data = data["embedded"]
53
+ # find the nested object
54
+ object = object.send(data["association"]).find(data["id"])
55
+ end
56
+ # once at the bottom, return the object
57
+ object
58
+ end
59
+
60
+ def serialize_object_for_session
61
+ # start at the bottom
62
+ object = source_object
63
+ result = nil
64
+ # work the way up the embeds
65
+ while object.embedded?
66
+ # select the relation for the parent object
67
+ parent_relation = relations.select do |k,v|
68
+ v.macro == :embedded_in && v.class_name == object._parent.class.name
69
+ end.values.first
70
+ # wrap the the result
71
+ result = {
72
+ embedded: {
73
+ association: parent_relation.inverse_of,
74
+ embedded: result,
75
+ id: object.id
76
+ }
77
+ }
78
+ # now act on the parent
79
+ object = object._parent
80
+ end
81
+ # when at the top level, store the class/id/result
82
+ result = { class_name: object.class.name, id: object.id, embedded: result }
83
+ # convert the result to JSON
84
+ MultiJson.dump(result)
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,5 @@
1
+ module Mongoid
2
+ module Publishable
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,2 @@
1
+ require "mongoid/publishable"
2
+ require "mongoid/publishable/version"
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ require "mongoid/publishable/version"
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "mongoid-publishable"
9
+ s.version = Mongoid::Publishable::VERSION
10
+ s.authors = ["Ryan Townsend"]
11
+ s.email = ["ryan@ryantownsend.co.uk"]
12
+ s.description = %q{A mixin for Mongoid document models allowing for publishing them after authentication}
13
+ s.summary = s.description
14
+ s.homepage = "https://github.com/ryantownsend/mongoid-publishable"
15
+
16
+ s.files = `git ls-files`.split($/)
17
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
18
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency "mongoid"
22
+ s.add_dependency "multi_json"
23
+ s.add_development_dependency "rake"
24
+ s.add_development_dependency "rspec"
25
+ s.add_development_dependency "simplecov"
26
+ end
data/spec/.DS_Store ADDED
Binary file
@@ -0,0 +1,17 @@
1
+ require "spec_helper"
2
+ require "mongoid/publishable/callback_collection"
3
+
4
+ describe Mongoid::Publishable::CallbackCollection do
5
+ let(:callback) { mock("callback") }
6
+ let(:contents) { [callback] }
7
+ subject { Mongoid::Publishable::CallbackCollection.new(contents) }
8
+
9
+ describe "#process" do
10
+ it "should call #process on each of it's items" do
11
+ object = mock("instance")
12
+ callback.should_receive(:process).with(object).and_return(true)
13
+ subject.process(object)
14
+ end
15
+ end
16
+
17
+ end
@@ -0,0 +1,46 @@
1
+ require "spec_helper"
2
+ require "mongoid/publishable/callback"
3
+
4
+ describe Mongoid::Publishable::Callback do
5
+ subject { Mongoid::Publishable::Callback }
6
+
7
+ describe "#initialize" do
8
+ it "should accept a block" do
9
+ callback = subject.new do |object|
10
+ puts "Done something"
11
+ end
12
+ expect(callback).to respond_to :process
13
+ end
14
+
15
+ it "should accept a symbol" do
16
+ callback = subject.new(:method_name)
17
+ expect(callback).to respond_to :process
18
+ end
19
+
20
+ it "should not accept two arguments" do
21
+ expect {
22
+ subject.new(:one, :two)
23
+ }.to raise_error(ArgumentError)
24
+ end
25
+ end
26
+
27
+ describe "#process" do
28
+ let(:object) { mock("instance", test: "123") }
29
+
30
+ context "when given a method name" do
31
+ it "should call the method on the given object" do
32
+ callback = subject.new(:test)
33
+ expect(callback.process(object)).to eq "123"
34
+ end
35
+ end
36
+
37
+ context "when given a block" do
38
+ it "should yield the block with the given object" do
39
+ callback = subject.new do |object|
40
+ object.test
41
+ end
42
+ expect(callback.process(object)).to eq "123"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,72 @@
1
+ require "spec_helper"
2
+ require "mongoid/publishable/callbacks"
3
+
4
+ describe Mongoid::Publishable::Callbacks do
5
+
6
+ context "a class that's included Mongoid::Publishable::Callbacks" do
7
+
8
+ subject do
9
+ CallbackableObject
10
+ end
11
+
12
+ describe "::after_publish_callbacks" do
13
+ it "should return an object that responds to #process" do
14
+ expect(subject.after_publish_callbacks).to respond_to :process
15
+ end
16
+ end
17
+
18
+ describe "::after_publish" do
19
+ it "should increment the callbacks by 1" do
20
+ subject.after_publish_callbacks.replace []
21
+ expect(subject.after_publish_callbacks.size).to eq 0
22
+ subject.after_publish(:method_name)
23
+ expect(subject.after_publish_callbacks.size).to eq 1
24
+ end
25
+
26
+ it "should accept a block" do
27
+ callback = subject.after_publish do |object|
28
+ puts "Done something"
29
+ end
30
+ expect(callback).to respond_to :process
31
+ end
32
+
33
+ it "should accept a symbol" do
34
+ callback = subject.after_publish(:method_name)
35
+ expect(callback).to respond_to :process
36
+ end
37
+ end
38
+
39
+ end # class
40
+
41
+ context "an instance class that's included Mongoid::Publishable::Callbacks" do
42
+
43
+ subject do
44
+ CallbackableObject.new
45
+ end
46
+
47
+ describe "#process_after_publish_callbacks" do
48
+ it "should process the callbacks" do
49
+ collection = subject.class.after_publish_callbacks
50
+ collection.should_receive(:process).with(subject).and_return(true)
51
+ expect(subject.process_after_publish_callbacks).to be_true
52
+ end
53
+ end
54
+
55
+ describe "#run_after_publish_callbacks?" do
56
+ context "by default" do
57
+ it "should return false" do
58
+ expect(subject.run_after_publish_callbacks?).to be_false
59
+ end
60
+ end
61
+
62
+ context "after calling #run_after_publish_callbacks" do
63
+ it "should return true" do
64
+ subject.run_after_publish_callbacks
65
+ expect(subject.run_after_publish_callbacks?).to be_true
66
+ end
67
+ end
68
+ end
69
+
70
+ end # instance
71
+
72
+ end
@@ -0,0 +1,106 @@
1
+ require "spec_helper"
2
+ require "mongoid/publishable/queue"
3
+
4
+ describe Mongoid::Publishable::Queue do
5
+
6
+ describe "the class" do
7
+ subject do
8
+ Mongoid::Publishable::Queue
9
+ end
10
+
11
+ describe "::load" do
12
+ context "given session data" do
13
+ it "should create an unpublished object for each line" do
14
+ data = %Q({ class_name: "Item", id: 123 }\n{ class_name: "Item", id: 123 })
15
+ expect(subject.load(data).size).to eq 2
16
+ end
17
+ end
18
+
19
+ context "given no session data" do
20
+ it "should return an empty queue" do
21
+ expect(subject.load.size).to eq 0
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ describe "an instance of the queue" do
28
+ let(:items) { [] }
29
+
30
+ subject do
31
+ Mongoid::Publishable::Queue.new(items)
32
+ end
33
+
34
+ describe "#publish_via" do
35
+ let(:item) do
36
+ mock("unpublished_item").tap do |item|
37
+ item.stub(:publish_via!).and_return(true)
38
+ end
39
+ end
40
+ let(:items) { [item] }
41
+
42
+ context "when all contents are published" do
43
+ before(:each) do
44
+ item.stub(:published?).and_return(true)
45
+ end
46
+
47
+ it "should empty the queue" do
48
+ expect(subject.size).to eq 1
49
+ subject.publish_via(mock("user"))
50
+ expect(subject.size).to eq 0
51
+ end
52
+ end
53
+
54
+ context "when one of the items cannot be published" do
55
+ before(:each) do
56
+ item.stub(:published?).and_return(false)
57
+ end
58
+
59
+ it "should leave one item in the queue" do
60
+ expect(subject.size).to eq 1
61
+ subject.publish_via(mock("user"))
62
+ expect(subject.size).to eq 1
63
+ end
64
+ end
65
+ end
66
+
67
+ describe "#dump" do
68
+ let(:item) do
69
+ mock("unpublished_item", serialize_for_session: "123")
70
+ end
71
+ let(:items) { [item, item] }
72
+
73
+ it "should serialize each object and join into a multi-line string" do
74
+ expect(subject.dump).to eq "123\n123"
75
+ end
76
+ end
77
+
78
+ describe "#push" do
79
+ context "when given a single item" do
80
+ it "the number of objects should be incremented by 1" do
81
+ count = subject.size
82
+ subject.push(mock("model"))
83
+ expect(subject.size).to eq count + 1
84
+ end
85
+ end
86
+
87
+ context "when given 2 items" do
88
+ it "the number of objects should be incremented by 2" do
89
+ count = subject.size
90
+ subject.push(mock("model"), mock("model"))
91
+ expect(subject.size).to eq count + 2
92
+ end
93
+ end
94
+
95
+ context "when given no items" do
96
+ it "the number of objects should not change" do
97
+ count = subject.size
98
+ subject.push
99
+ expect(subject.size).to eq count
100
+ end
101
+ end
102
+ end
103
+
104
+ end # instance
105
+
106
+ end