asynchronic 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: c7a82bc550c9f5c81ebf6ec87c33051ab31d645d
4
+ data.tar.gz: 0571213c9a3a35d9770f4f81032fb9e35c8c1dd4
5
+ SHA512:
6
+ metadata.gz: 0b8a197203e07e67f36af15d8dd4736517f0aba1fff0696f462a76a9e61a881f1935dc4401f3d0e330c77d4b382ae762fa71ae3d327ee7b7599726ac67105a34
7
+ data.tar.gz: 4ecbd031498315ae41331ddc09c8a1a72e6eba232f194c695a3feb638c1bb1820e7d225cedaae8899e291a1207984ed8b2bb84d9706a82fc71cbda9569eea05d
data/.coveralls.yml ADDED
@@ -0,0 +1,2 @@
1
+ service_name: travis-ci
2
+ repo_token: OLptFnwS4b790xMkLwgB6xP6hvdCm6HiL
data/.gitignore ADDED
@@ -0,0 +1,18 @@
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
18
+ .idea/
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0
5
+ - jruby
6
+ services:
7
+ - redis-server
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in asynchronic.gemspec
4
+ gemspec
5
+
6
+ gem 'coveralls', require: false
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Gabriel Naiman
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,104 @@
1
+ # Asynchronic
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/asynchronic.png)](https://rubygems.org/gems/asynchronic)
4
+ [![Build Status](https://travis-ci.org/gabynaiman/asynchronic.png?branch=master)](https://travis-ci.org/gabynaiman/asynchronic)
5
+ [![Coverage Status](https://coveralls.io/repos/gabynaiman/asynchronic/badge.png?branch=master)](https://coveralls.io/r/gabynaiman/asynchronic?branch=master)
6
+ [![Code Climate](https://codeclimate.com/github/gabynaiman/asynchronic.png)](https://codeclimate.com/github/gabynaiman/asynchronic)
7
+ [![Dependency Status](https://gemnasium.com/gabynaiman/asynchronic.png)](https://gemnasium.com/gabynaiman/asynchronic)
8
+
9
+ DSL for asynchronic pipeline using queues over Redis
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ gem 'asynchronic'
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install asynchronic
24
+
25
+ ## Usage
26
+
27
+ ### Basic usage
28
+
29
+ class Job
30
+ extend Asynchronic::Pipeline
31
+
32
+ step :step_name do
33
+ ...
34
+ end
35
+ end
36
+
37
+ Job.run
38
+
39
+ Asynchronic::Worker.start
40
+
41
+ ### Enque job in specific queue
42
+
43
+ class Job
44
+ extend Asynchronic::Pipeline
45
+
46
+ queue :queue_name
47
+
48
+ step :step_name do
49
+ ...
50
+ end
51
+ end
52
+
53
+ Job.run
54
+
55
+ Asynchronic::Worker.start :queue_name
56
+
57
+ ### Pipeline with shared context
58
+
59
+ class Job
60
+ extend Asynchronic::Pipeline
61
+
62
+ step :first do |ctx|
63
+ ctx[:c] = ctx[:a] + ctx[:b]
64
+ 100
65
+ end
66
+
67
+ step :second do |ctx, input|
68
+ input * ctx[:c] # 300
69
+ end
70
+ end
71
+
72
+ Job.run a: 1, b: 2
73
+
74
+ Asynchronic::Worker.start
75
+
76
+ ### Specify queue for each step
77
+
78
+ class Job
79
+ extend Asynchronic::Pipeline
80
+
81
+ step :first_queue, queue: :queue1 do
82
+ ...
83
+ end
84
+
85
+ step :second_queue, queue: ->(ctx){ctx[:dynamic_queue]} do
86
+ ...
87
+ end
88
+ end
89
+
90
+ Job.run dynamic_queue: :queue2
91
+
92
+ [:queue1, :queue2].map do |queue|
93
+ Thread.new do
94
+ Asynchronic::Worker.start queue
95
+ end
96
+ end
97
+
98
+ ## Contributing
99
+
100
+ 1. Fork it
101
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
102
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
103
+ 4. Push to the branch (`git push origin my-new-feature`)
104
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new(:spec) do |t|
5
+ t.libs << 'spec'
6
+ t.pattern = 'spec/**/*_spec.rb'
7
+ t.verbose = false
8
+ end
9
+
10
+ task default: :spec
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'asynchronic/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'asynchronic'
8
+ spec.version = Asynchronic::VERSION
9
+ spec.authors = ['Gabriel Naiman']
10
+ spec.email = ['gabynaiman@gmail.com']
11
+ spec.description = 'DSL for asynchronic pipeline'
12
+ spec.summary = 'DSL for asynchronic pipeline using queues over Redis'
13
+ spec.homepage = 'https://github.com/gabynaiman/asynchronic'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'ost', '~> 0.1'
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.3'
24
+ spec.add_development_dependency 'rake'
25
+ spec.add_development_dependency 'minitest', '~> 4.7'
26
+ spec.add_development_dependency 'turn', '~> 0.9'
27
+ spec.add_development_dependency 'simplecov'
28
+ end
@@ -0,0 +1,48 @@
1
+ require 'ost'
2
+ require 'securerandom'
3
+ require 'base64'
4
+ require 'logger'
5
+ require 'fileutils'
6
+
7
+ Dir.glob(File.expand_path('asynchronic/*.rb', File.dirname(__FILE__))).sort.each { |f| require f }
8
+
9
+ module Asynchronic
10
+
11
+ def self.default_queue
12
+ @default_queue ||= :asynchronic
13
+ end
14
+
15
+ def self.default_queue=(name)
16
+ @default_queue = name
17
+ end
18
+
19
+ def self.logger
20
+ @logger ||= Logger.new($stdout)
21
+ end
22
+
23
+ def self.logger=(logger)
24
+ @logger = logger
25
+ end
26
+
27
+ def self.connect_redis(options)
28
+ Ost.connect options
29
+ @redis = Redis.new options
30
+ end
31
+
32
+ def self.redis
33
+ @redis ||= Redis.current
34
+ end
35
+
36
+ def self.archiving_path
37
+ @archiving_path ||= File.join(Dir.home, '.asynchronic', 'data')
38
+ end
39
+
40
+ def self.archiving_path=(path)
41
+ @archiving_path = path
42
+ end
43
+
44
+ def self.archiving_file(name)
45
+ File.join archiving_path, "#{name}.bin"
46
+ end
47
+
48
+ end
@@ -0,0 +1,61 @@
1
+ module Asynchronic
2
+ module Persistent
3
+
4
+ def self.included(base)
5
+ base.send :include, InstanceMethods
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ module InstanceMethods
10
+
11
+ def id
12
+ @id
13
+ end
14
+
15
+ def save
16
+ @id ||= SecureRandom.uuid
17
+ nest.set Marshal.dump(self)
18
+ end
19
+
20
+ def delete
21
+ return unless id
22
+ nest.del
23
+ end
24
+
25
+ def archive
26
+ return unless id
27
+ FileUtils.mkpath(Asynchronic.archiving_path) unless Dir.exists?(Asynchronic.archiving_path)
28
+ File.write Asynchronic.archiving_file(id), Base64.encode64(Marshal.dump(self))
29
+ delete
30
+ end
31
+
32
+ def nest
33
+ self.class.nest[id]
34
+ end
35
+
36
+ end
37
+
38
+ module ClassMethods
39
+
40
+ def create(*args, &block)
41
+ new(*args, &block).tap(&:save)
42
+ end
43
+
44
+ def find(id)
45
+ if nest[id].get
46
+ Marshal.load nest[id].get
47
+ elsif File.exists?(Asynchronic.archiving_file(id))
48
+ Marshal.load(Base64.decode64(File.read(Asynchronic.archiving_file(id))))
49
+ else
50
+ nil
51
+ end
52
+ end
53
+
54
+ def nest
55
+ @nest ||= Nest.new self.name, Asynchronic.redis
56
+ end
57
+
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,23 @@
1
+ module Asynchronic
2
+ module Pipeline
3
+
4
+ Step = Struct.new :name, :options, :block
5
+
6
+ def queue(name=nil)
7
+ name ? @queue = name : @queue
8
+ end
9
+
10
+ def step(name, options={}, &block)
11
+ steps << Step.new(name, options, block)
12
+ end
13
+
14
+ def steps
15
+ @steps ||= []
16
+ end
17
+
18
+ def run(context={})
19
+ Process.enqueue self, context
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,80 @@
1
+ module Asynchronic
2
+ class Process
3
+
4
+ include Persistent
5
+
6
+ Child = Struct.new :status, :output
7
+
8
+ attr_reader :pipeline
9
+ attr_reader :context
10
+ attr_reader :children
11
+
12
+ def initialize(pipeline, context={})
13
+ @pipeline = pipeline
14
+ @context = context
15
+ @children = pipeline.steps.map { Child.new :pending }
16
+ end
17
+
18
+ def enqueue(queue=nil)
19
+ q = queue || pipeline.queue || Asynchronic.default_queue
20
+ Ost[q.is_a?(Proc) ? q.call(context) : q].push id
21
+ end
22
+
23
+ def run
24
+ current_child.tap do |i|
25
+ log "Running: #{id} (child: #{i})" do
26
+ children[i].status = :running
27
+ save
28
+
29
+ current_input = previous_child?(i) ? children[previous_child(i)].output : nil
30
+ children[i].output = pipeline.steps[i].block.call(context, current_input)
31
+ children[i].status = :finalized
32
+ save
33
+
34
+ if next_child?(i)
35
+ enqueue(pipeline.steps[next_child(i)].options[:queue])
36
+ else
37
+ archive
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def self.enqueue(pipeline, context={})
44
+ process = Process.create pipeline, context
45
+ process.enqueue(pipeline.steps.first.options[:queue])
46
+ process.id
47
+ end
48
+
49
+ private
50
+
51
+ def current_child
52
+ children.index { |c| c.status == :pending }
53
+ end
54
+
55
+ def previous_child(index=current_step)
56
+ index - 1
57
+ end
58
+
59
+ def previous_child?(index=current_step)
60
+ previous_child(index) >= 0
61
+ end
62
+
63
+ def next_child(index=current_step)
64
+ index + 1
65
+ end
66
+
67
+ def next_child?(index=current_step)
68
+ next_child(index) < children.count
69
+ end
70
+
71
+ def log(message)
72
+ start = Time.now
73
+ Asynchronic.logger.info('Asynchronic') { "#{message} - Start" }
74
+ result = yield
75
+ Asynchronic.logger.info('Asynchronic') { "#{message} - End (Time: #{Time.now - start})" }
76
+ result
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,3 @@
1
+ module Asynchronic
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,27 @@
1
+ module Asynchronic
2
+ class Worker
3
+
4
+ attr_reader :queue
5
+
6
+ def initialize(queue=nil)
7
+ @queue = queue || Asynchronic.default_queue
8
+ end
9
+
10
+ def start
11
+ Signal.trap('INT') { stop }
12
+
13
+ Ost[@queue].pop do |pid|
14
+ Process.find(pid).run
15
+ end
16
+ end
17
+
18
+ def stop
19
+ Ost[@queue].stop
20
+ end
21
+
22
+ def self.start(queue=nil)
23
+ new(queue).tap(&:start)
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,8 @@
1
+ require 'simplecov'
2
+ require 'coveralls'
3
+
4
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
5
+ SimpleCov::Formatter::HTMLFormatter,
6
+ Coveralls::SimpleCov::Formatter
7
+ ]
8
+ SimpleCov.start
@@ -0,0 +1,122 @@
1
+ require 'minitest_helper'
2
+ require 'jobs'
3
+
4
+ describe 'Integration' do
5
+
6
+ before do
7
+ Registry.clear
8
+ end
9
+
10
+ def start_and_stop_worker(queue=nil)
11
+ worker = Asynchronic::Worker.new queue
12
+ Thread.new do
13
+ sleep 0.1
14
+ while Nest.new('ost')[worker.queue].exists; end
15
+ worker.stop
16
+ end
17
+ worker.start
18
+ end
19
+
20
+ def exist_queue?(queue)
21
+ Nest.new('ost')[queue].exists
22
+ end
23
+
24
+ it 'Job defaults' do
25
+ SingleStepJob.queue.must_be_nil
26
+ SingleStepJob.steps.count.must_equal 1
27
+ SingleStepJob.steps[0].name.must_equal :step_name
28
+ SingleStepJob.steps[0].options.must_equal Hash.new
29
+ SingleStepJob.steps[0].block.class.must_equal Proc
30
+ SingleStepJob.must_respond_to :run
31
+ end
32
+
33
+ it 'Process defaults' do
34
+ pid = SingleStepJob.run
35
+
36
+ pid.wont_be_nil
37
+
38
+ process = Asynchronic::Process.find pid
39
+
40
+ process.pipeline.must_equal SingleStepJob
41
+ process.context.must_equal Hash.new
42
+ process.children.count.must_equal 1
43
+ process.children[0].status.must_equal :pending
44
+ process.children[0].output.must_be_nil
45
+ end
46
+
47
+ describe 'Execution' do
48
+
49
+ it 'One step job' do
50
+ SingleStepJob.queue.must_be_nil
51
+ refute exist_queue? Asynchronic.default_queue
52
+
53
+ pid = SingleStepJob.run
54
+
55
+ assert exist_queue? Asynchronic.default_queue
56
+ Registry.must_be_empty
57
+
58
+ start_and_stop_worker
59
+
60
+ process = Asynchronic::Process.find pid
61
+ process.children[0].status.must_equal :finalized
62
+ process.children[0].output.must_equal :single_step_job
63
+
64
+ Registry.to_a.must_equal [:single_step_job]
65
+ end
66
+
67
+ it 'Two steps with specific queue and context arguments' do
68
+ TwoStepsWithSpecificQueueJob.queue.wont_be_nil
69
+ refute exist_queue? TwoStepsWithSpecificQueueJob.queue
70
+
71
+ pid = TwoStepsWithSpecificQueueJob.run value1: 10
72
+
73
+ assert exist_queue? TwoStepsWithSpecificQueueJob.queue
74
+ Registry.must_be_empty
75
+
76
+ start_and_stop_worker TwoStepsWithSpecificQueueJob.queue
77
+
78
+ process = Asynchronic::Process.find pid
79
+ process.context.must_equal value1: 10, value2: 5
80
+ process.children[0].status.must_equal :finalized
81
+ process.children[0].output.must_equal 11
82
+ process.children[1].status.must_equal :finalized
83
+ process.children[1].output.must_equal 55
84
+
85
+ Registry.to_a.must_equal [11, 55]
86
+ end
87
+
88
+ it 'Steps with different queues (fixed and contextual)' do
89
+ MultipleQueuesJob.queue.must_be_nil
90
+ refute exist_queue? :queue1
91
+ refute exist_queue? :queue2
92
+
93
+ pid = MultipleQueuesJob.run dynamic_queue: :queue2
94
+
95
+ assert exist_queue? :queue1
96
+ refute exist_queue? :queue2
97
+ Registry.must_be_empty
98
+
99
+ start_and_stop_worker :queue1
100
+
101
+ process = Asynchronic::Process.find pid
102
+ process.children[0].status.must_equal :finalized
103
+ process.children[1].status.must_equal :pending
104
+
105
+ refute exist_queue? :queue1
106
+ assert exist_queue? :queue2
107
+ Registry.to_a.must_equal [:first_queue]
108
+
109
+ start_and_stop_worker :queue2
110
+
111
+ process = Asynchronic::Process.find pid
112
+ process.children[0].status.must_equal :finalized
113
+ process.children[1].status.must_equal :finalized
114
+
115
+ refute exist_queue? :queue1
116
+ refute exist_queue? :queue2
117
+ Registry.to_a.must_equal [:first_queue, :second_queue]
118
+ end
119
+
120
+ end
121
+
122
+ end
data/spec/jobs.rb ADDED
@@ -0,0 +1,58 @@
1
+ class Registry
2
+ extend Enumerable
3
+
4
+ def self.add(arg)
5
+ Asynchronic.logger.debug('Asynchronic') { "Registry: #{arg}" }
6
+ elements << arg
7
+ arg
8
+ end
9
+
10
+ def self.clear
11
+ elements.clear
12
+ end
13
+
14
+ def self.each(&block)
15
+ elements.each(&block)
16
+ end
17
+
18
+ def self.empty?
19
+ !any?
20
+ end
21
+
22
+ private
23
+
24
+ def self.elements
25
+ @elements ||= []
26
+ end
27
+ end
28
+
29
+ class SingleStepJob
30
+ extend Asynchronic::Pipeline
31
+ step :step_name do
32
+ Registry.add :single_step_job
33
+ end
34
+ end
35
+
36
+ class TwoStepsWithSpecificQueueJob
37
+ extend Asynchronic::Pipeline
38
+ queue :specific_queue
39
+ step :first do |ctx|
40
+ ctx[:value2] = ctx[:value1] / 2
41
+ Registry.add ctx[:value1] + 1
42
+ end
43
+ step :second do |ctx, input|
44
+ Registry.add input * ctx[:value2]
45
+ end
46
+ end
47
+
48
+ class MultipleQueuesJob
49
+ extend Asynchronic::Pipeline
50
+ step :first_queue, queue: :queue1 do
51
+ Registry.add :first_queue
52
+ end
53
+ step :second_queue, queue: ->(ctx){ctx[:dynamic_queue]} do
54
+ Registry.add :second_queue
55
+ end
56
+ end
57
+
58
+
@@ -0,0 +1,31 @@
1
+ require 'coverage_helper'
2
+ require 'minitest/autorun'
3
+ require 'turn'
4
+ require 'asynchronic'
5
+
6
+ Turn.config do |c|
7
+ c.format = :pretty
8
+ c.natural = true
9
+ end
10
+
11
+ logger = Logger.new($stdout)
12
+ logger.level = Logger::ERROR
13
+ Asynchronic.logger = logger
14
+
15
+ Asynchronic.connect_redis host: 'localhost', port: 6379
16
+
17
+ Asynchronic.default_queue = 'asynchronic_test'
18
+
19
+ Asynchronic.archiving_path = File.expand_path('../tmp', File.dirname(__FILE__))
20
+
21
+ class MiniTest::Spec
22
+
23
+ before do
24
+ Redis.current.flushdb
25
+ end
26
+
27
+ def redis
28
+ Redis.current
29
+ end
30
+
31
+ end
@@ -0,0 +1,88 @@
1
+ require 'minitest_helper'
2
+
3
+ describe Asynchronic::Persistent do
4
+
5
+ Dummy = Struct.new :string, :hash, :array do
6
+ include Asynchronic::Persistent
7
+ end
8
+
9
+ def dummy_attributes
10
+ ['text', {key1: 'value1', key2: 'value2'}, [1,2,3]]
11
+ end
12
+
13
+ def assert_dummy(obj)
14
+ obj.string.must_equal 'text'
15
+ obj.hash.must_equal key1: 'value1', key2: 'value2'
16
+ obj.array.must_equal [1,2,3]
17
+ end
18
+
19
+ describe 'Instance methods' do
20
+
21
+ let(:dummy) { Dummy.new *dummy_attributes }
22
+
23
+ it 'Nest instance identifier' do
24
+ dummy.define_singleton_method(:id) { '123456' }
25
+ dummy.nest.must_equal 'Dummy:123456'
26
+ end
27
+
28
+ it 'Save' do
29
+ dummy.id.must_equal nil
30
+ dummy.save
31
+ dummy.id.wont_equal nil
32
+
33
+ redis.keys.must_include dummy.nest
34
+
35
+ assert_dummy Marshal.load(redis.get(dummy.nest))
36
+ end
37
+
38
+ it 'Delete' do
39
+ dummy.save
40
+ redis.keys.must_include dummy.nest
41
+
42
+ dummy.delete
43
+ redis.keys.wont_include dummy.nest
44
+ end
45
+
46
+ it 'Archive' do
47
+ dummy.save
48
+ redis.keys.must_include dummy.nest
49
+ refute File.exists?(Asynchronic.archiving_file(dummy.id))
50
+
51
+ dummy.archive
52
+ redis.keys.wont_include dummy.nest
53
+ assert File.exists?(Asynchronic.archiving_file(dummy.id))
54
+
55
+ assert_dummy Marshal.load(Base64.decode64(File.read(Asynchronic.archiving_file(dummy.id))))
56
+ end
57
+
58
+ end
59
+
60
+ describe 'Class methods' do
61
+
62
+ it 'Nest class identifier' do
63
+ Dummy.nest.must_equal 'Dummy'
64
+ end
65
+
66
+ it 'Create' do
67
+ dummy = Dummy.create *dummy_attributes
68
+
69
+ redis.keys.must_include dummy.nest
70
+ assert_dummy Marshal.load(redis.get(dummy.nest))
71
+ end
72
+
73
+ it 'Find' do
74
+ dummy = Dummy.create *dummy_attributes
75
+
76
+ assert_dummy Dummy.find(dummy.id)
77
+ end
78
+
79
+ it 'Find archived' do
80
+ dummy = Dummy.create *dummy_attributes
81
+ dummy.archive
82
+
83
+ assert_dummy Dummy.find(dummy.id)
84
+ end
85
+
86
+ end
87
+
88
+ end
metadata ADDED
@@ -0,0 +1,152 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: asynchronic
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Gabriel Naiman
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ost
15
+ prerelease: false
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '0.1'
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '0.1'
26
+ type: :runtime
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ prerelease: false
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.3'
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.3'
40
+ type: :development
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ prerelease: false
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ prerelease: false
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '4.7'
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '4.7'
68
+ type: :development
69
+ - !ruby/object:Gem::Dependency
70
+ name: turn
71
+ prerelease: false
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '0.9'
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '0.9'
82
+ type: :development
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ prerelease: false
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :development
97
+ description: DSL for asynchronic pipeline
98
+ email:
99
+ - gabynaiman@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".coveralls.yml"
105
+ - ".gitignore"
106
+ - ".travis.yml"
107
+ - Gemfile
108
+ - LICENSE.txt
109
+ - README.md
110
+ - Rakefile
111
+ - asynchronic.gemspec
112
+ - lib/asynchronic.rb
113
+ - lib/asynchronic/persistent.rb
114
+ - lib/asynchronic/pipeline.rb
115
+ - lib/asynchronic/process.rb
116
+ - lib/asynchronic/version.rb
117
+ - lib/asynchronic/worker.rb
118
+ - spec/coverage_helper.rb
119
+ - spec/integration_spec.rb
120
+ - spec/jobs.rb
121
+ - spec/minitest_helper.rb
122
+ - spec/persistent_spec.rb
123
+ homepage: https://github.com/gabynaiman/asynchronic
124
+ licenses:
125
+ - MIT
126
+ metadata: {}
127
+ post_install_message:
128
+ rdoc_options: []
129
+ require_paths:
130
+ - lib
131
+ required_ruby_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ requirements: []
142
+ rubyforge_project:
143
+ rubygems_version: 2.1.5
144
+ signing_key:
145
+ specification_version: 4
146
+ summary: DSL for asynchronic pipeline using queues over Redis
147
+ test_files:
148
+ - spec/coverage_helper.rb
149
+ - spec/integration_spec.rb
150
+ - spec/jobs.rb
151
+ - spec/minitest_helper.rb
152
+ - spec/persistent_spec.rb