merging-queue 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.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitignore +4 -0
- data/.rspec +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +20 -0
- data/README.md +146 -0
- data/Rakefile +11 -0
- data/lib/generators/merging-queue.rb +14 -0
- data/lib/generators/merging-queue/activity/activity_generator.rb +17 -0
- data/lib/generators/merging-queue/activity/templates/activity.rb +5 -0
- data/lib/generators/merging-queue/migration/migration_generator.rb +17 -0
- data/lib/generators/merging-queue/migration/templates/migration.rb +30 -0
- data/lib/merging-queue.rb +9 -0
- data/lib/merging-queue/actor.rb +54 -0
- data/lib/merging-queue/definition.rb +48 -0
- data/lib/merging-queue/definition_dsl.rb +48 -0
- data/lib/merging-queue/errors.rb +44 -0
- data/lib/merging-queue/queued_task.rb +237 -0
- data/lib/merging-queue/version.rb +3 -0
- data/merging-queue.gemspec +29 -0
- data/test/migrations/001_create_queued_tasks.rb +30 -0
- data/test/migrations/002_create_articles.rb +11 -0
- data/test/migrations/003_create_users.rb +8 -0
- data/test/migrations/004_add_nonstandard_to_activities.rb +7 -0
- data/test/migrations/005_create_volumes.rb +9 -0
- data/test/test_helper.rb +73 -0
- data/test/unit/activity_test.rb +92 -0
- data/test/unit/actor_test.rb +46 -0
- data/test/unit/definition_dsl_test.rb +29 -0
- data/test/unit/definition_test.rb +51 -0
- metadata +142 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7dae3e92ad88cafbb75132665eae4f3207052388
|
4
|
+
data.tar.gz: b1feaf6f3cc0ec5e0f8bd35e9ae42b3682fe5494
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fd9822d92b529e05891f578404fe341a102eb2a921f933588f51a484ab70b52ea95418ed3c410107cf21dc1fb2031d034c11cfb7abfb676674e9a8d2a7fe26f5
|
7
|
+
data.tar.gz: 8250336736f7c5621b30d69d47f0b8f43dd3657c4c5c251160a0a62ea38091f925e36550a992e4fca9a06c83be296384b168b685d62606a2d0f442401d671fda
|
data/.document
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2013 Andreas Saebjoernsen
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
# MergingQueue
|
2
|
+
|
3
|
+
MergingQueue is a simple gem for grouping tasks by type and time using the ActiveRecord ODM framework and
|
4
|
+
background jobs.
|
5
|
+
|
6
|
+
This gem is inspired by Streama by Christopher Pappas.
|
7
|
+
|
8
|
+
[](http://travis-ci.org/digitalplaywright/merging-queue) [](https://gemnasium.com/digitalplaywright/merging-queue) [](https://codeclimate.com/github/digitalplaywright/merging-queue)
|
9
|
+
|
10
|
+
|
11
|
+
## Install
|
12
|
+
|
13
|
+
gem install merging-queue
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
### Create migration for queued_tasks and migrate the database (in your Rails project):
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
rails g merging-queue:migration
|
21
|
+
rake db:migrate
|
22
|
+
```
|
23
|
+
|
24
|
+
### Define Queued Task
|
25
|
+
|
26
|
+
Create an QueuedTask model and define the queued_tasks and the fields you would like to cache within the queued_task.
|
27
|
+
|
28
|
+
An queued_task consists of an actor, a verb, an act_object, and a target.
|
29
|
+
|
30
|
+
``` ruby
|
31
|
+
class QueuedTask < ActiveRecord::Base
|
32
|
+
include MergingQueue::QueuedTask
|
33
|
+
|
34
|
+
queued_task :new_enquiry do
|
35
|
+
actor :User
|
36
|
+
act_object :Article
|
37
|
+
act_target :Volume
|
38
|
+
end
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
The queued_task verb is implied from the queued_task name, in the above example the verb is :new_enquiry
|
43
|
+
|
44
|
+
The act_object may be the entity performing the queued_task, or the entity on which the queued_task was performed.
|
45
|
+
e.g John(actor) shared a video(act_object)
|
46
|
+
|
47
|
+
The target is the act_object that the verb is enacted on.
|
48
|
+
e.g. Geraldine(actor) posted a photo(act_object) to her album(target)
|
49
|
+
|
50
|
+
This is based on the QueuedTask Streams 1.0 specification (http://queued_taskstrea.ms)
|
51
|
+
|
52
|
+
### Setup Actors
|
53
|
+
|
54
|
+
Include the Actor module in a class and override the default followers method.
|
55
|
+
|
56
|
+
``` ruby
|
57
|
+
class User < ActiveRecord::Base
|
58
|
+
include MergingQueue::Actor
|
59
|
+
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
|
64
|
+
|
65
|
+
### Publishing QueuedTask
|
66
|
+
|
67
|
+
In your controller or background worker:
|
68
|
+
|
69
|
+
``` ruby
|
70
|
+
current_user.publish_queued_task(:new_enquiry, :act_object => @enquiry, :target => @listing)
|
71
|
+
```
|
72
|
+
|
73
|
+
This will publish the queued_task to the mongoid act_objects returned by the #followers method in the Actor.
|
74
|
+
|
75
|
+
|
76
|
+
## Retrieving QueuedTask
|
77
|
+
|
78
|
+
To retrieve all queued_task for an actor
|
79
|
+
|
80
|
+
``` ruby
|
81
|
+
current_user.queued_tasks
|
82
|
+
```
|
83
|
+
|
84
|
+
To retrieve and filter to a particular queued_task type
|
85
|
+
|
86
|
+
``` ruby
|
87
|
+
current_user.queued_tasks(:verb => 'new_enquiry')
|
88
|
+
```
|
89
|
+
|
90
|
+
#### Options
|
91
|
+
|
92
|
+
Additional options can be required:
|
93
|
+
|
94
|
+
``` ruby
|
95
|
+
class QueuedTask < ActiveRecord::Base
|
96
|
+
include MergingQueue::QueuedTask
|
97
|
+
|
98
|
+
queued_task :new_enquiry do
|
99
|
+
actor :User
|
100
|
+
act_object :Article
|
101
|
+
act_target :Volume
|
102
|
+
option :country
|
103
|
+
option :city
|
104
|
+
end
|
105
|
+
end
|
106
|
+
```
|
107
|
+
|
108
|
+
The option fields are stored using the ActiveRecord 'store' feature.
|
109
|
+
|
110
|
+
|
111
|
+
#### Bond type
|
112
|
+
|
113
|
+
A verb can have one bond type. This bond type can be used to classify and quickly retrieve
|
114
|
+
queued_task feed items that belong to a particular aggregate feed, like e.g the global feed.
|
115
|
+
|
116
|
+
``` ruby
|
117
|
+
class QueuedTask < ActiveRecord::Base
|
118
|
+
include MergingQueue::QueuedTask
|
119
|
+
|
120
|
+
queued_task :new_enquiry do
|
121
|
+
actor :User
|
122
|
+
act_object :Article
|
123
|
+
act_target :Volume
|
124
|
+
bond_type :global
|
125
|
+
end
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
129
|
+
### Poll for changes and empty queue
|
130
|
+
|
131
|
+
There is a poll changes interface that will group tasks by first actor and then verb.
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
QueuedTask.poll_for_changes() do |verb, hash|
|
135
|
+
#verb is the verb the changes are group by
|
136
|
+
#hash has format: {:actor => _actor /* actor is the */,
|
137
|
+
# :act_objects => act_objects /* all objects from matching tasks */,
|
138
|
+
# :act_object_ids => act_object_ids /* all object ids from matching tasks */,
|
139
|
+
# :act_targets => act_targets /* all targets from matching tasks */ ,
|
140
|
+
# :act_target_ids => act_target_ids /* all target ids from matching tasks}
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
144
|
+
|
145
|
+
|
146
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rails/generators/named_base'
|
2
|
+
|
3
|
+
module MergingQueue
|
4
|
+
# A generator module with QueuedTask table schema.
|
5
|
+
module Generators
|
6
|
+
# A base module
|
7
|
+
module Base
|
8
|
+
# Get path for migration template
|
9
|
+
def source_root
|
10
|
+
@_merging-queue_source_root ||= File.expand_path(File.join('../merging-queue', generator_name, 'templates'), __FILE__)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'generators/queue_collapser'
|
2
|
+
require 'rails/generators/active_record'
|
3
|
+
|
4
|
+
module MergingQueue
|
5
|
+
module Generators
|
6
|
+
# QueuedTask generator that creates queued_task model file from template
|
7
|
+
class QueuedTaskGenerator < ActiveRecord::Generators::Base
|
8
|
+
extend Base
|
9
|
+
|
10
|
+
argument :name, :type => :string, :default => 'queued_task'
|
11
|
+
# Create model in project's folder
|
12
|
+
def generate_files
|
13
|
+
copy_file 'queued_task.rb', "app/models/#{name}.rb"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'generators/queue_collapser'
|
2
|
+
require 'rails/generators/active_record'
|
3
|
+
|
4
|
+
module LiveStream
|
5
|
+
module Generators
|
6
|
+
# Migration generator that creates migration file from template
|
7
|
+
class MigrationGenerator < ActiveRecord::Generators::Base
|
8
|
+
extend Base
|
9
|
+
|
10
|
+
argument :name, :type => :string, :default => 'create_queued_tasks'
|
11
|
+
# Create migration in project's folder
|
12
|
+
def generate_files
|
13
|
+
migration_template 'migration.rb', "db/migrate/#{name}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Migration responsible for creating a table with queued_tasks
|
2
|
+
class CreateQueuedTasks < ActiveRecord::Migration
|
3
|
+
# Create table
|
4
|
+
def self.up
|
5
|
+
create_table :queued_tasks do |t|
|
6
|
+
t.belongs_to :actor, :polymorphic => true
|
7
|
+
t.belongs_to :act_object, :polymorphic => true
|
8
|
+
t.belongs_to :act_target, :polymorphic => true
|
9
|
+
|
10
|
+
t.string :verb
|
11
|
+
t.string :description
|
12
|
+
t.string :options
|
13
|
+
t.string :bond_type
|
14
|
+
|
15
|
+
t.time :publish_on
|
16
|
+
t.string :state
|
17
|
+
|
18
|
+
t.timestamps
|
19
|
+
end
|
20
|
+
|
21
|
+
add_index :queued_tasks, [:verb]
|
22
|
+
add_index :queued_tasks, [:actor_id, :actor_type]
|
23
|
+
add_index :queued_tasks, [:act_object_id, :act_object_type]
|
24
|
+
add_index :queued_tasks, [:act_target_id, :act_target_type]
|
25
|
+
end
|
26
|
+
# Drop table
|
27
|
+
def self.down
|
28
|
+
drop_table :queued_tasks
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'active_support'
|
3
|
+
require 'active_support/core_ext/module/delegation.rb'
|
4
|
+
require "merging-queue/version"
|
5
|
+
require "merging-queue/actor"
|
6
|
+
require "merging-queue/queued_task"
|
7
|
+
require "merging-queue/definition"
|
8
|
+
require "merging-queue/definition_dsl"
|
9
|
+
require "merging-queue/errors"
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module MergingQueue
|
2
|
+
|
3
|
+
module Actor
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
cattr_accessor :queued_task_klass
|
8
|
+
|
9
|
+
has_many :queued_tasks, :class_name => "QueuedTask", :as => :actor
|
10
|
+
has_many :act_object_queued_tasks, :class_name => "QueuedTask", :as => :act_object
|
11
|
+
has_many :act_target_queued_tasks, :class_name => "QueuedTask", :as => :act_target
|
12
|
+
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
|
18
|
+
def queued_task_class(klass)
|
19
|
+
self.queued_task_klass = klass.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
# Publishes the queued_task to the receivers
|
26
|
+
#
|
27
|
+
# @param [ Hash ] options The options to publish with.
|
28
|
+
#
|
29
|
+
# @example publish an queued_task with a act_object and act_target
|
30
|
+
# current_user.publish_queued_task(:enquiry, :act_object => @enquiry, :act_target => @listing)
|
31
|
+
#
|
32
|
+
def publish_queued_task(name, cur_publish_on, options={})
|
33
|
+
cur_publish_on = Time.now + cur_publish_on if cur_publish_on.kind_of?(Fixnum)
|
34
|
+
raise "Expected Time type. Got:" + cur_publish_on.class.name unless cur_publish_on.kind_of?(Time)
|
35
|
+
queued_task_class.publish(name, cur_publish_on, {:actor => self}.merge(options))
|
36
|
+
end
|
37
|
+
|
38
|
+
def queued_task_class
|
39
|
+
@queued_task_klass ||= queued_task_klass ? queued_task_klass.classify.constantize : ::QueuedTask
|
40
|
+
end
|
41
|
+
|
42
|
+
def queued_merging_tasks(options = {})
|
43
|
+
|
44
|
+
if options.empty?
|
45
|
+
queued_tasks
|
46
|
+
else
|
47
|
+
queued_tasks.where(options)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module MergingQueue
|
2
|
+
|
3
|
+
class Definition
|
4
|
+
|
5
|
+
attr_reader :name, :actor, :act_object, :act_target, :grouped_actor, :bond_type, :options
|
6
|
+
|
7
|
+
# @param dsl [MergingQueue::DefinitionDSL] A DSL act_object
|
8
|
+
def initialize(definition)
|
9
|
+
@name = definition[:name]
|
10
|
+
@actor = definition[:actor] || nil
|
11
|
+
@act_object = definition[:act_object] || nil
|
12
|
+
@act_target = definition[:act_target] || nil
|
13
|
+
@grouped_actor = definition[:grouped_actor] || nil
|
14
|
+
@bond_type = definition[:bond_type] || nil
|
15
|
+
@options = definition[:options] || []
|
16
|
+
end
|
17
|
+
|
18
|
+
#
|
19
|
+
# Registers a new definition
|
20
|
+
#
|
21
|
+
# @param definition [Definition] The definition to register
|
22
|
+
# @return [Definition] Returns the registered definition
|
23
|
+
def self.register(definition)
|
24
|
+
return false unless definition.is_a? DefinitionDSL
|
25
|
+
definition = new(definition)
|
26
|
+
self.registered << definition
|
27
|
+
return definition || false
|
28
|
+
end
|
29
|
+
|
30
|
+
# List of registered definitions
|
31
|
+
# @return [Array<MergingQueue::Definition>]
|
32
|
+
def self.registered
|
33
|
+
@definitions ||= []
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.find(name)
|
37
|
+
unless definition = registered.find{|definition| definition.name == name.to_sym}
|
38
|
+
raise MergingQueue::InvalidQueuedTask, "Could not find a definition for `#{name}`"
|
39
|
+
else
|
40
|
+
definition
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
|
3
|
+
module MergingQueue
|
4
|
+
|
5
|
+
class DefinitionDSL
|
6
|
+
|
7
|
+
attr_reader :attributes
|
8
|
+
|
9
|
+
def initialize(name)
|
10
|
+
@attributes = {
|
11
|
+
:name => name.to_sym,
|
12
|
+
:actor => nil,
|
13
|
+
:act_object => nil,
|
14
|
+
:act_target => nil,
|
15
|
+
:grouped_actor => nil,
|
16
|
+
:reverses => nil,
|
17
|
+
:bond_type => nil,
|
18
|
+
:options => nil
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_option(option)
|
23
|
+
@attributes[:options] ||= []
|
24
|
+
|
25
|
+
@attributes[:options] << option
|
26
|
+
end
|
27
|
+
|
28
|
+
def option(text)
|
29
|
+
add_option( text )
|
30
|
+
end
|
31
|
+
|
32
|
+
delegate :[], :to => :@attributes
|
33
|
+
|
34
|
+
def self.data_methods(*args)
|
35
|
+
args.each do |method|
|
36
|
+
define_method method do |*args|
|
37
|
+
|
38
|
+
@attributes[method] = args[0]
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
data_methods :actor, :act_object, :act_target, :grouped_actor, :bond_type
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module MergingQueue
|
2
|
+
|
3
|
+
class MergingQueueError < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
class InvalidQueuedTask < MergingQueueError
|
7
|
+
end
|
8
|
+
|
9
|
+
# This error is raised when an act_object isn't defined
|
10
|
+
# as an actor, act_object or act_target
|
11
|
+
#
|
12
|
+
# Example:
|
13
|
+
#
|
14
|
+
# <tt>InvalidField.new('field_name')</tt>
|
15
|
+
class InvalidData < MergingQueueError
|
16
|
+
attr_reader :message
|
17
|
+
|
18
|
+
def initialize message
|
19
|
+
@message = "Invalid Data: #{message}"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
# This error is raised when trying to store a field that doesn't exist
|
25
|
+
#
|
26
|
+
# Example:
|
27
|
+
#
|
28
|
+
# <tt>InvalidField.new('field_name')</tt>
|
29
|
+
class InvalidField < MergingQueueError
|
30
|
+
attr_reader :message
|
31
|
+
|
32
|
+
def initialize message
|
33
|
+
@message = "Invalid Field: #{message}"
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
class QueuedTaskNotSaved < MergingQueueError
|
39
|
+
end
|
40
|
+
|
41
|
+
class NoFollowersDefined < MergingQueueError
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
module MergingQueue
|
2
|
+
module QueuedTask
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
|
7
|
+
store :options
|
8
|
+
|
9
|
+
belongs_to :actor, :polymorphic => true
|
10
|
+
belongs_to :act_object, :polymorphic => true
|
11
|
+
belongs_to :act_target, :polymorphic => true
|
12
|
+
|
13
|
+
validates_presence_of :actor_id, :actor_type, :verb
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
|
18
|
+
def poll_for_changes()
|
19
|
+
#if block_given?
|
20
|
+
|
21
|
+
::QueuedTask.where('state = ? AND publish_on <= ?', 'initial', Time.now).distinct(:actor_id).each do |actor_id|
|
22
|
+
|
23
|
+
::QueuedTask.where('state = ? AND actor_id = ? AND publish_on <= ?', 'initial', actor_id, Time.now).select(:verb).uniq.each do |verb|
|
24
|
+
|
25
|
+
changes_for_actor = ::QueuedTask.where(:actor_id => actor_id, :state => 'initial', :verb => verb['verb'].to_s)
|
26
|
+
|
27
|
+
begin
|
28
|
+
yield verb, accumulate_changes(changes_for_actor)
|
29
|
+
|
30
|
+
changes_for_actor.destroy_all
|
31
|
+
|
32
|
+
rescue ActiveRecord::RecordNotFound
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
#---- general helpers
|
43
|
+
|
44
|
+
#---- add up all actors, act_objects and act_targets in the search results.
|
45
|
+
# it does not matter what is where
|
46
|
+
def accumulate_changes(search_result)
|
47
|
+
act_targets = []
|
48
|
+
act_target_ids = []
|
49
|
+
act_objects = []
|
50
|
+
act_object_ids = []
|
51
|
+
|
52
|
+
_actor = search_result.first.actor
|
53
|
+
|
54
|
+
search_result.each do |result|
|
55
|
+
result.update_attributes(:state => 'pending')
|
56
|
+
|
57
|
+
act_object = result.act_object
|
58
|
+
act_target = result.act_target
|
59
|
+
|
60
|
+
if act_object != nil && !act_object_ids.include?(act_object.id)
|
61
|
+
act_objects << act_object
|
62
|
+
act_object_ids << act_object.id
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
if act_target != nil && !act_target_ids.include?(act_target.id)
|
67
|
+
act_targets << act_target
|
68
|
+
act_target_ids << act_target.id
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
{:actor => _actor, :act_objects => act_objects, :act_object_ids => act_object_ids,
|
75
|
+
:act_targets => act_targets, :act_target_ids => act_target_ids}
|
76
|
+
end
|
77
|
+
|
78
|
+
# Defines a new QueuedTask2 type and registers a definition
|
79
|
+
#
|
80
|
+
# @param [ String ] name The name of the queued_task
|
81
|
+
#
|
82
|
+
# @example Define a new queued_task
|
83
|
+
# queued_task(:enquiry) do
|
84
|
+
# actor :user, :cache => [:full_name]
|
85
|
+
# act_object :enquiry, :cache => [:subject]
|
86
|
+
# act_target :listing, :cache => [:title]
|
87
|
+
# end
|
88
|
+
#
|
89
|
+
# @return [Definition] Returns the registered definition
|
90
|
+
def queued_task(name, &block)
|
91
|
+
definition = MergingQueue::DefinitionDSL.new(name)
|
92
|
+
definition.instance_eval(&block)
|
93
|
+
MergingQueue::Definition.register(definition)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Publishes an queued_task using an queued_task name and data
|
97
|
+
#
|
98
|
+
# @param [ String ] verb The verb of the queued_task
|
99
|
+
# @param [ Hash ] data The data to initialize the queued_task with.
|
100
|
+
#
|
101
|
+
# @return [MergingQueue::QueuedTask2] An QueuedTask instance with data
|
102
|
+
def publish(verb, cur_publish_on, data)
|
103
|
+
new.publish({:verb => verb, :publish_on => cur_publish_on}.merge(data))
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
|
110
|
+
# Publishes the queued_task to the receivers
|
111
|
+
#
|
112
|
+
# @param [ Hash ] options The options to publish with.
|
113
|
+
#
|
114
|
+
def publish(data = {})
|
115
|
+
assign_properties(data)
|
116
|
+
|
117
|
+
self
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
def refresh_data
|
122
|
+
save(:validate => false)
|
123
|
+
end
|
124
|
+
|
125
|
+
protected
|
126
|
+
|
127
|
+
def assign_properties(data = {})
|
128
|
+
|
129
|
+
self.verb = data.delete(:verb)
|
130
|
+
|
131
|
+
write_attribute(:publish_on, data[:publish_on])
|
132
|
+
data.delete(:publish_on)
|
133
|
+
|
134
|
+
self.state = 'initial'
|
135
|
+
|
136
|
+
[:actor, :act_object, :act_target].each do |type|
|
137
|
+
|
138
|
+
cur_object = data[type]
|
139
|
+
|
140
|
+
unless cur_object
|
141
|
+
if definition.send(type.to_sym)
|
142
|
+
raise verb.to_json
|
143
|
+
#raise MergingQueue::InvalidData.new(type)
|
144
|
+
else
|
145
|
+
next
|
146
|
+
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
class_sym = cur_object.class.name.to_sym
|
151
|
+
|
152
|
+
raise MergingQueue::InvalidData.new(class_sym) unless definition.send(type) == class_sym
|
153
|
+
|
154
|
+
case type
|
155
|
+
when :actor
|
156
|
+
self.actor = cur_object
|
157
|
+
when :act_object
|
158
|
+
self.act_object = cur_object
|
159
|
+
when :act_target
|
160
|
+
self.act_target = cur_object
|
161
|
+
else
|
162
|
+
raise "unknown type"
|
163
|
+
end
|
164
|
+
|
165
|
+
data.delete(type)
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
[:grouped_actor].each do |group|
|
170
|
+
|
171
|
+
|
172
|
+
grp_object = data[group]
|
173
|
+
|
174
|
+
if grp_object == nil
|
175
|
+
if definition.send(group.to_sym)
|
176
|
+
raise verb.to_json
|
177
|
+
#raise MergingQueue::InvalidData.new(group)
|
178
|
+
else
|
179
|
+
next
|
180
|
+
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
grp_object.each do |cur_obj|
|
185
|
+
raise MergingQueue::InvalidData.new(class_sym) unless definition.send(group) == cur_obj.class.name.to_sym
|
186
|
+
|
187
|
+
self.grouped_actors << cur_obj
|
188
|
+
|
189
|
+
end
|
190
|
+
|
191
|
+
data.delete(group)
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
cur_bond_type = definition.send(:bond_type)
|
196
|
+
|
197
|
+
if cur_bond_type
|
198
|
+
write_attribute( :bond_type, cur_bond_type.to_s )
|
199
|
+
end
|
200
|
+
|
201
|
+
def_options = definition.send(:options)
|
202
|
+
def_options.each do |cur_option|
|
203
|
+
cur_object = data[cur_option]
|
204
|
+
|
205
|
+
if cur_object
|
206
|
+
|
207
|
+
if cur_option == :description
|
208
|
+
self.description = cur_object
|
209
|
+
else
|
210
|
+
options[cur_option] = cur_object
|
211
|
+
end
|
212
|
+
data.delete(cur_option)
|
213
|
+
|
214
|
+
else
|
215
|
+
#all options defined must be used
|
216
|
+
raise Streama::InvalidData.new(cur_object[0])
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
if data.size > 0
|
221
|
+
raise "unexpected arguments: " + data.to_json
|
222
|
+
end
|
223
|
+
|
224
|
+
|
225
|
+
|
226
|
+
self.save
|
227
|
+
|
228
|
+
|
229
|
+
end
|
230
|
+
|
231
|
+
def definition
|
232
|
+
@definition ||= MergingQueue::Definition.find(verb)
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
end
|
237
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "merging-queue/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "merging-queue"
|
7
|
+
s.version = MergingQueue::VERSION
|
8
|
+
s.authors = ["Andreas Saebjoernsen"]
|
9
|
+
s.email = ["andreas.saebjoernsen@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{QueuedTask Streams for rails}
|
12
|
+
s.description = %q{MergingQueue is a simple gem for grouping tasks by type and time using the ActiveRecord ODM framework and background jobs}
|
13
|
+
s.homepage = 'https://github.com/digitalplaywright/merging-queue'
|
14
|
+
|
15
|
+
s.rubyforge_project = "merging-queue"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.required_ruby_version = '>= 1.9.3'
|
23
|
+
|
24
|
+
s.add_dependency 'activerecord', '>= 3'
|
25
|
+
s.add_dependency 'activesupport', '>= 3'
|
26
|
+
s.add_dependency 'actionpack', '>= 3'
|
27
|
+
s.add_development_dependency 'rake'
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Migration responsible for creating a table with queued_tasks
|
2
|
+
class CreateQueuedTasks < ActiveRecord::Migration
|
3
|
+
# Create table
|
4
|
+
def self.up
|
5
|
+
create_table :queued_tasks do |t|
|
6
|
+
t.belongs_to :actor, :polymorphic => true
|
7
|
+
t.belongs_to :act_object, :polymorphic => true
|
8
|
+
t.belongs_to :act_target, :polymorphic => true
|
9
|
+
|
10
|
+
t.string :verb
|
11
|
+
t.string :description
|
12
|
+
t.string :options
|
13
|
+
t.string :bond_type
|
14
|
+
|
15
|
+
t.time :publish_on
|
16
|
+
t.string :state
|
17
|
+
|
18
|
+
t.timestamps
|
19
|
+
end
|
20
|
+
|
21
|
+
add_index :queued_tasks, [:verb]
|
22
|
+
add_index :queued_tasks, [:actor_id, :actor_type]
|
23
|
+
add_index :queued_tasks, [:act_object_id, :act_object_type]
|
24
|
+
add_index :queued_tasks, [:act_target_id, :act_target_type]
|
25
|
+
end
|
26
|
+
# Drop table
|
27
|
+
def self.down
|
28
|
+
drop_table :queued_tasks
|
29
|
+
end
|
30
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bundler"
|
3
|
+
Bundler.setup(:default, :test)
|
4
|
+
|
5
|
+
$:.unshift File.expand_path('../../lib/', __FILE__)
|
6
|
+
require 'active_support/testing/setup_and_teardown'
|
7
|
+
require 'merging-queue'
|
8
|
+
require 'minitest/autorun'
|
9
|
+
|
10
|
+
#LiveStream.config # touch config to load ORM, needed in some separate tests
|
11
|
+
|
12
|
+
require 'active_record'
|
13
|
+
require 'active_record/connection_adapters/sqlite3_adapter'
|
14
|
+
|
15
|
+
|
16
|
+
class ActiveSupport::TestCase
|
17
|
+
# Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
|
18
|
+
#
|
19
|
+
# Note: You'll currently still have to declare fixtures explicitly in integration tests
|
20
|
+
# -- they do not yet inherit this setting
|
21
|
+
#fixtures :all
|
22
|
+
|
23
|
+
# Add more helper methods to be used by all tests here...
|
24
|
+
end
|
25
|
+
|
26
|
+
class QueuedTask < ActiveRecord::Base
|
27
|
+
include MergingQueue::QueuedTask
|
28
|
+
|
29
|
+
queued_task :new_enquiry do
|
30
|
+
actor :User
|
31
|
+
act_object :Article
|
32
|
+
act_target :Volume
|
33
|
+
#option :description
|
34
|
+
end
|
35
|
+
|
36
|
+
queued_task :test_description do
|
37
|
+
actor :User
|
38
|
+
act_object :Article
|
39
|
+
act_target :Volume
|
40
|
+
option :description
|
41
|
+
end
|
42
|
+
|
43
|
+
queued_task :test_option do
|
44
|
+
actor :User
|
45
|
+
act_object :Article
|
46
|
+
act_target :Volume
|
47
|
+
option :country
|
48
|
+
end
|
49
|
+
|
50
|
+
queued_task :test_bond_type do
|
51
|
+
actor :User
|
52
|
+
act_object :Article
|
53
|
+
act_target :Volume
|
54
|
+
bond_type :global
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
class User < ActiveRecord::Base
|
60
|
+
include MergingQueue::Actor
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
class Article < ActiveRecord::Base
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
class Volume < ActiveRecord::Base
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
|
73
|
+
ActiveRecord::Migrator.migrate(File.expand_path('../migrations', __FILE__))
|
@@ -0,0 +1,92 @@
|
|
1
|
+
class QueuedTaskTest < ActiveSupport::TestCase
|
2
|
+
|
3
|
+
def test_truth
|
4
|
+
assert true
|
5
|
+
end
|
6
|
+
|
7
|
+
def test_register_definition
|
8
|
+
|
9
|
+
@definition = QueuedTask.queued_task(:test_queued_task) do
|
10
|
+
actor :user, :cache => [:full_name]
|
11
|
+
act_object :listing, :cache => [:title, :full_address]
|
12
|
+
act_target :listing, :cache => [:title]
|
13
|
+
end
|
14
|
+
|
15
|
+
assert @definition.is_a?(MergingQueue::Definition)
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_publish_new_queued_task
|
20
|
+
_user = User.create()
|
21
|
+
_article = Article.create()
|
22
|
+
_volume = Volume.create()
|
23
|
+
|
24
|
+
_queued_task = QueuedTask.publish(:new_enquiry, Time.now, :actor => _user, :act_object => _article, :act_target => _volume)
|
25
|
+
|
26
|
+
assert _queued_task.persisted?
|
27
|
+
#_queued_task.should be_an_instance_of QueuedTask
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_description
|
32
|
+
_user = User.create()
|
33
|
+
_article = Article.create()
|
34
|
+
_volume = Volume.create()
|
35
|
+
|
36
|
+
_description = "this is a test"
|
37
|
+
_queued_task = QueuedTask.publish(:test_description, Time.now, :actor => _user, :act_object => _article, :act_target => _volume,
|
38
|
+
:description => _description )
|
39
|
+
|
40
|
+
assert _queued_task.description == _description
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_options
|
45
|
+
_user = User.create()
|
46
|
+
_article = Article.create()
|
47
|
+
_volume = Volume.create()
|
48
|
+
|
49
|
+
_country = "denmark"
|
50
|
+
_queued_task = QueuedTask.publish(:test_option, Time.now, :actor => _user, :act_object => _article, :act_target => _volume,
|
51
|
+
:country => _country )
|
52
|
+
|
53
|
+
assert _queued_task.options[:country] == _country
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_bond_type
|
58
|
+
_user = User.create()
|
59
|
+
_article = Article.create()
|
60
|
+
_volume = Volume.create()
|
61
|
+
|
62
|
+
_queued_task = QueuedTask.publish(:test_bond_type, Time.now, :actor => _user, :act_object => _article, :act_target => _volume)
|
63
|
+
|
64
|
+
assert _queued_task.bond_type == 'global'
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_poll_changes
|
69
|
+
|
70
|
+
_user = User.create()
|
71
|
+
_article = Article.create()
|
72
|
+
_volume = Volume.create()
|
73
|
+
|
74
|
+
QueuedTask.publish(:test_bond_type, Time.now, :actor => _user, :act_object => _article, :act_target => _volume)
|
75
|
+
|
76
|
+
assert QueuedTask.all.size > 0
|
77
|
+
|
78
|
+
QueuedTask.poll_for_changes() do |verb, hash|
|
79
|
+
#assert hash[:actor].id == _user.id
|
80
|
+
end
|
81
|
+
|
82
|
+
assert QueuedTask.all.size == 0
|
83
|
+
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class ActorTest < ActiveSupport::TestCase
|
2
|
+
|
3
|
+
|
4
|
+
def test_publish_queued_task
|
5
|
+
|
6
|
+
_user = User.create()
|
7
|
+
_article = Article.create()
|
8
|
+
_volume = Volume.create()
|
9
|
+
|
10
|
+
queued_task = _user.publish_queued_task(:new_enquiry, Time.now, :act_object => _article, :act_target => _volume)
|
11
|
+
|
12
|
+
assert queued_task.persisted?
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_retrieves_the_stream_for_an_actor
|
17
|
+
_user = User.create()
|
18
|
+
_article = Article.create()
|
19
|
+
_volume = Volume.create()
|
20
|
+
|
21
|
+
_user.publish_queued_task(:new_enquiry, Time.now, :act_object => _article, :act_target => _volume)
|
22
|
+
_user.publish_queued_task(:new_enquiry, Time.now, :act_object => _article, :act_target => _volume)
|
23
|
+
|
24
|
+
assert _user.queued_tasks.size == 2
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def test_retrieves_the_stream_for_a_particular_queued_task_type
|
30
|
+
_user = User.create()
|
31
|
+
_article = Article.create()
|
32
|
+
_volume = Volume.create()
|
33
|
+
|
34
|
+
_user.publish_queued_task(:new_enquiry, Time.now, :act_object => _article, :act_target => _volume)
|
35
|
+
_user.publish_queued_task(:new_enquiry, Time.now, :act_object => _article, :act_target => _volume)
|
36
|
+
_user.publish_queued_task(:test_bond_type, Time.now, :act_object => _article, :act_target => _volume)
|
37
|
+
|
38
|
+
assert _user.queued_merging_tasks(:verb => 'new_enquiry').size == 2
|
39
|
+
assert _user.queued_merging_tasks(:bond_type => 'global').size == 1
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class DefinitionDslTest < ActiveSupport::TestCase
|
2
|
+
|
3
|
+
def definition_dsl
|
4
|
+
MergingQueue::DefinitionDSL.new(:new_enquiry)
|
5
|
+
end
|
6
|
+
|
7
|
+
def test_initializes_with_name
|
8
|
+
assert definition_dsl.attributes[:name] == :new_enquiry
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_adds_an_actor_to_the_definition
|
12
|
+
dsl = definition_dsl
|
13
|
+
dsl.actor(:User)
|
14
|
+
assert dsl.attributes[:actor] == :User
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_adds_an_act_object_to_the_definition
|
18
|
+
dsl = definition_dsl
|
19
|
+
dsl.act_object(:Article)
|
20
|
+
assert dsl.attributes[:act_object] == :Article
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_adds_a_act_target_to_the_definition
|
24
|
+
dsl = definition_dsl
|
25
|
+
dsl.act_target(:Volume)
|
26
|
+
assert dsl.attributes[:act_target] == :Volume
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class DefinitionTest < ActiveSupport::TestCase
|
2
|
+
|
3
|
+
def definition_dsl
|
4
|
+
dsl = MergingQueue::DefinitionDSL.new(:new_enquiry)
|
5
|
+
dsl.actor(:User)
|
6
|
+
dsl.act_object(:Article)
|
7
|
+
dsl.act_target(:Volume)
|
8
|
+
dsl
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_initialization
|
12
|
+
_definition_dsl = definition_dsl
|
13
|
+
_definition = MergingQueue::Definition.new(_definition_dsl)
|
14
|
+
|
15
|
+
assert _definition.actor == :User
|
16
|
+
assert _definition.act_object == :Article
|
17
|
+
assert _definition.act_target == :Volume
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_register_definition_and_return_new_definition
|
22
|
+
|
23
|
+
assert MergingQueue::Definition.register(definition_dsl).is_a?(MergingQueue::Definition)
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_register_invalid_definition
|
28
|
+
|
29
|
+
assert MergingQueue::Definition.register(false) == false
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_return_registered_definitions
|
34
|
+
|
35
|
+
MergingQueue::Definition.register(definition_dsl)
|
36
|
+
assert MergingQueue::Definition.registered.size > 0
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_return_definition_by_name
|
41
|
+
assert MergingQueue::Definition.find(:new_enquiry).name == :new_enquiry
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_raise_exception_if_invalid_queued_task
|
46
|
+
|
47
|
+
assert_raises(MergingQueue::InvalidQueuedTask){ MergingQueue::Definition.find(:unknown_queued_task) }
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
metadata
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: merging-queue
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andreas Saebjoernsen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-07-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: actionpack
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '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
|
+
description: MergingQueue is a simple gem for grouping tasks by type and time using
|
70
|
+
the ActiveRecord ODM framework and background jobs
|
71
|
+
email:
|
72
|
+
- andreas.saebjoernsen@gmail.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- .document
|
78
|
+
- .gitignore
|
79
|
+
- .rspec
|
80
|
+
- .travis.yml
|
81
|
+
- Gemfile
|
82
|
+
- LICENSE.txt
|
83
|
+
- README.md
|
84
|
+
- Rakefile
|
85
|
+
- lib/generators/merging-queue.rb
|
86
|
+
- lib/generators/merging-queue/activity/activity_generator.rb
|
87
|
+
- lib/generators/merging-queue/activity/templates/activity.rb
|
88
|
+
- lib/generators/merging-queue/migration/migration_generator.rb
|
89
|
+
- lib/generators/merging-queue/migration/templates/migration.rb
|
90
|
+
- lib/merging-queue.rb
|
91
|
+
- lib/merging-queue/actor.rb
|
92
|
+
- lib/merging-queue/definition.rb
|
93
|
+
- lib/merging-queue/definition_dsl.rb
|
94
|
+
- lib/merging-queue/errors.rb
|
95
|
+
- lib/merging-queue/queued_task.rb
|
96
|
+
- lib/merging-queue/version.rb
|
97
|
+
- merging-queue.gemspec
|
98
|
+
- test/migrations/001_create_queued_tasks.rb
|
99
|
+
- test/migrations/002_create_articles.rb
|
100
|
+
- test/migrations/003_create_users.rb
|
101
|
+
- test/migrations/004_add_nonstandard_to_activities.rb
|
102
|
+
- test/migrations/005_create_volumes.rb
|
103
|
+
- test/test_helper.rb
|
104
|
+
- test/unit/activity_test.rb
|
105
|
+
- test/unit/actor_test.rb
|
106
|
+
- test/unit/definition_dsl_test.rb
|
107
|
+
- test/unit/definition_test.rb
|
108
|
+
homepage: https://github.com/digitalplaywright/merging-queue
|
109
|
+
licenses: []
|
110
|
+
metadata: {}
|
111
|
+
post_install_message:
|
112
|
+
rdoc_options: []
|
113
|
+
require_paths:
|
114
|
+
- lib
|
115
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
116
|
+
requirements:
|
117
|
+
- - '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: 1.9.3
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
requirements: []
|
126
|
+
rubyforge_project: merging-queue
|
127
|
+
rubygems_version: 2.0.4
|
128
|
+
signing_key:
|
129
|
+
specification_version: 4
|
130
|
+
summary: QueuedTask Streams for rails
|
131
|
+
test_files:
|
132
|
+
- test/migrations/001_create_queued_tasks.rb
|
133
|
+
- test/migrations/002_create_articles.rb
|
134
|
+
- test/migrations/003_create_users.rb
|
135
|
+
- test/migrations/004_add_nonstandard_to_activities.rb
|
136
|
+
- test/migrations/005_create_volumes.rb
|
137
|
+
- test/test_helper.rb
|
138
|
+
- test/unit/activity_test.rb
|
139
|
+
- test/unit/actor_test.rb
|
140
|
+
- test/unit/definition_dsl_test.rb
|
141
|
+
- test/unit/definition_test.rb
|
142
|
+
has_rdoc:
|