hay 0.0.1.pre.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +34 -0
  3. data/.travis.yml +17 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE +21 -0
  6. data/README.md +3 -0
  7. data/Rakefile +60 -0
  8. data/hay.gemspec +30 -0
  9. data/lib/hay/consumer.rb +27 -0
  10. data/lib/hay/dispatcher.rb +23 -0
  11. data/lib/hay/message.rb +28 -0
  12. data/lib/hay/queue.rb +22 -0
  13. data/lib/hay/route.rb +29 -0
  14. data/lib/hay/router.rb +25 -0
  15. data/lib/hay/routes.rb +24 -0
  16. data/lib/hay/task/decorator.rb +35 -0
  17. data/lib/hay/task/exception/transient_exception.rb +10 -0
  18. data/lib/hay/task/exception/unknown_template_error.rb +16 -0
  19. data/lib/hay/task/exception.rb +11 -0
  20. data/lib/hay/task/flow.rb +41 -0
  21. data/lib/hay/task/hydrator/registry.rb +21 -0
  22. data/lib/hay/task/hydrator.rb +21 -0
  23. data/lib/hay/task/hydrators.rb +28 -0
  24. data/lib/hay/task/registry.rb +16 -0
  25. data/lib/hay/task/resolver/hash.rb +19 -0
  26. data/lib/hay/task/resolver/registry.rb +11 -0
  27. data/lib/hay/task/resolver/task.rb +18 -0
  28. data/lib/hay/task/resolver.rb +17 -0
  29. data/lib/hay/task/resolvers.rb +20 -0
  30. data/lib/hay/task/resulter.rb +23 -0
  31. data/lib/hay/task/template/hash.rb +21 -0
  32. data/lib/hay/task/template/hydrator.rb +23 -0
  33. data/lib/hay/task/template/registry.rb +18 -0
  34. data/lib/hay/task/template/task.rb +28 -0
  35. data/lib/hay/task/template.rb +18 -0
  36. data/lib/hay/task/templates.rb +23 -0
  37. data/lib/hay/task.rb +29 -0
  38. data/lib/hay/tasks.rb +18 -0
  39. data/lib/hay/version.rb +4 -0
  40. data/lib/hay.rb +19 -0
  41. data/rakelib/hay/rake.rb +36 -0
  42. data/test/alfalfa.log +47 -0
  43. data/test/integration/hay_test.rb +239 -0
  44. data/test/simplecov_helper.rb +31 -0
  45. data/test/unit/hay/dispatcher_test.rb +38 -0
  46. data/test/unit/hay/message_test.rb +43 -0
  47. data/test/unit/hay/route_test.rb +56 -0
  48. data/test/unit/hay/router_test.rb +26 -0
  49. data/test/unit/hay/routes_test.rb +37 -0
  50. data/test/unit/hay/task/decorator_test.rb +68 -0
  51. data/test/unit/hay/task/flow_test.rb +45 -0
  52. data/test/unit/hay/task/hydrator_test.rb +38 -0
  53. data/test/unit/hay/task/hydrators_test.rb +26 -0
  54. data/test/unit/hay/task/resulter_test.rb +27 -0
  55. data/test/unit/hay/task/template/hash_test.rb +30 -0
  56. data/test/unit/hay/task/template/hydrator_test.rb +30 -0
  57. data/test/unit/hay/task/template/task_test.rb +33 -0
  58. data/test/unit/hay/task/template_test.rb +36 -0
  59. data/test/unit/hay/task_test.rb +6 -0
  60. data/test/unit/test_helper.rb +24 -0
  61. metadata +206 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3e9f58b9c8931713ab80709d18de6eacf67cf121
4
+ data.tar.gz: 1f80d87fc28483308026bd62a36c228ea2238989
5
+ SHA512:
6
+ metadata.gz: 0f20a6d70a05ce284af2a3c8b22bd040a426a393b358a937d1f6e8fa8d1e418b1e4a009f5497b6953bc67041f13d69d96cab4474fd700247ec6e70ebf3f7be97
7
+ data.tar.gz: a062287b084f6fc0f6b2f1e9636ae5f6f732edf3504dcdbe01868edcb8debdca8088f5e42ebccf07fc7109a3017614f7e2cec68ab535f28549d7f9cbe439434f
data/.gitignore ADDED
@@ -0,0 +1,34 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ # for a library or gem, you might want to ignore these files since the code is
28
+ # intended to run in multiple environments; otherwise, check them in:
29
+ Gemfile.lock
30
+ .ruby-version
31
+ .ruby-gemset
32
+
33
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
+ .rvmrc
data/.travis.yml ADDED
@@ -0,0 +1,17 @@
1
+ language: ruby
2
+
3
+ env:
4
+ global:
5
+ - COVERAGE=true
6
+ matrix:
7
+ - TEST_SUITE=unit
8
+ - TEST_SUITE=integration
9
+
10
+ script: "bundle exec rake test:$TEST_SUITE"
11
+
12
+ rvm:
13
+ - "1.9.3"
14
+ - "2.1.3"
15
+ - "ruby-head"
16
+ - "jruby-19mode"
17
+ - "rbx-2"
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem 'coveralls', group: :test, require: false
4
+ gem 'codeclimate-test-reporter', group: :test, require: nil
5
+
6
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Ed Carrel
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
data/README.md ADDED
@@ -0,0 +1,3 @@
1
+ Hay
2
+ =======
3
+ A workflow definition framework.
data/Rakefile ADDED
@@ -0,0 +1,60 @@
1
+ require 'rake/testtask'
2
+
3
+ $LOAD_PATH.push("rakelib")
4
+ require 'hay/rake'
5
+
6
+ require 'coveralls/rake/task'
7
+
8
+ Edger::Rake::Tasks.new do |t|
9
+ end
10
+
11
+ namespace :cov do
12
+
13
+ desc "Rake tests and then open report"
14
+ task :run do
15
+ puts 'Running Tests...'
16
+ `rake`
17
+ puts 'Opening Report.'
18
+ path = File.expand_path('../../../', __FILE__)
19
+ `open #{path}/coverage/index.html`
20
+ end
21
+
22
+ desc "View coverage report"
23
+ task :report do
24
+ path = File.expand_path('../../../', __FILE__)
25
+ `open #{path}/coverage/index.html`
26
+ end
27
+ end
28
+
29
+ namespace :coinstar do
30
+ task :test do
31
+ Rake::Task['test'].invoke
32
+ end
33
+ end
34
+
35
+ task :test do
36
+ Rake::Task['test:unit'].invoke
37
+ Rake::Task['test:integration'].invoke
38
+ end
39
+
40
+ namespace :test do
41
+ Rake::TestTask.new("integration") do |t|
42
+ t.libs << "test"
43
+ t.libs << "config"
44
+ t.test_files = FileList['test/integration/**/*_test.rb']
45
+ t.verbose = true
46
+ end
47
+
48
+ Rake::TestTask.new("unit") do |t|
49
+ t.libs << "test"
50
+ t.libs << "config"
51
+ t.test_files = FileList['test/unit/**/*_test.rb']
52
+ t.verbose = true
53
+ end
54
+ end
55
+
56
+ Coveralls::RakeTask.new
57
+
58
+ task :test_with_coveralls => ['test:unit', 'test:integration', 'coveralls:push']
59
+
60
+ task :default => :test_with_coveralls
data/hay.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'hay/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "hay"
7
+ spec.version = Hay::VERSION
8
+ spec.summary = "A workflow definition framework."
9
+ spec.description = "A generic workflow definition framework."
10
+ spec.platform = "ruby"
11
+
12
+ spec.homepage = "https://github.com/azanar/hay"
13
+ spec.license = "MIT"
14
+
15
+ spec.authors = ["Ed Carrel"]
16
+ spec.email = ["edward@carrel.org"]
17
+
18
+ spec.files = `git ls-files -z`.split("\x0")
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_runtime_dependency 'punchout', '~> 0'
24
+
25
+ spec.add_development_dependency 'test-unit', '~> 3'
26
+ spec.add_development_dependency 'mocha', '~> 1'
27
+ spec.add_development_dependency 'simplecov', '~> 0'
28
+ spec.add_development_dependency "bundler", "~> 1.6"
29
+ spec.add_development_dependency "rake", "~> 10.0"
30
+ end
@@ -0,0 +1,27 @@
1
+ require 'hay'
2
+
3
+ require 'hay/queue'
4
+ require 'hay/task/resolver'
5
+ require 'hay/task/resolvers'
6
+
7
+ module Hay
8
+ module Consumer
9
+ def initialize(agent)
10
+ @queue = Hay::Queue.new(self, agent)
11
+ end
12
+
13
+ def ours?(task)
14
+ task_names.include?(task.task_name)
15
+ end
16
+
17
+ def push(task)
18
+ resolved_task = Hay::Task::Resolver.new(task)
19
+ @queue.push(resolved_task)
20
+ @queue.run
21
+ end
22
+
23
+ def task_names
24
+ @task_names ||= tasks.map(&:task_name)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+ require 'hay'
2
+
3
+ require 'hay/router'
4
+ require 'hay/message'
5
+
6
+ module Hay
7
+ class Dispatcher
8
+ def initialize(consumer, agent)
9
+ @consumer = consumer
10
+ @agent = agent
11
+ @router = Hay::Router.new(@agent)
12
+ end
13
+
14
+ def push(task)
15
+ if @consumer.ours?(task)
16
+ @consumer.push(task)
17
+ else
18
+ message = Hay::Message.new(task)
19
+ @router.push(message)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ require 'hay/routes'
2
+
3
+ module Hay
4
+ class Message
5
+ def initialize(task)
6
+ @task = task
7
+ if @task.class == Hash
8
+ raise "god damn it all #{@task}"
9
+ end
10
+ end
11
+
12
+ attr_reader :task
13
+
14
+ def payload
15
+ @payload ||= @task.dehydrate
16
+ end
17
+
18
+ def destination
19
+ @destination ||= build_destination
20
+ end
21
+
22
+ private
23
+
24
+ def build_destination
25
+ Hay::Routes.for_name(@task.task_name) or raise "Could not find route for task #{@task.task_name}"
26
+ end
27
+ end
28
+ end
data/lib/hay/queue.rb ADDED
@@ -0,0 +1,22 @@
1
+ require 'hay/dispatcher'
2
+
3
+ module Hay
4
+ class Queue
5
+ def initialize(consumer, agent)
6
+ @queue = []
7
+ @dispatcher = Hay::Dispatcher.new(consumer, agent)
8
+ end
9
+
10
+ def push(task)
11
+ @queue << task
12
+ end
13
+
14
+ def run
15
+ until @queue.empty?
16
+ task = @queue.shift
17
+ task.process(@dispatcher)
18
+ end
19
+ end
20
+ end
21
+ end
22
+
data/lib/hay/route.rb ADDED
@@ -0,0 +1,29 @@
1
+ module Hay
2
+ module Route
3
+ class << self
4
+ def queue_name
5
+ raise NotImplementedException
6
+ end
7
+
8
+ def included(route)
9
+ Hay::Routes.register(route)
10
+ end
11
+ end
12
+
13
+ def initialize(agent)
14
+ @agent = agent
15
+ end
16
+
17
+ def tasks
18
+ raise NotImplementedException
19
+ end
20
+
21
+ def push(message)
22
+ @agent.publish(message)
23
+ end
24
+
25
+ def ours?(message)
26
+ tasks.include?(message.task.class)
27
+ end
28
+ end
29
+ end
data/lib/hay/router.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'hay/dispatcher'
2
+ require 'hay/routes'
3
+
4
+ module Hay
5
+ class Router
6
+ def initialize(agent)
7
+ @agent = agent
8
+ end
9
+
10
+ def push(message)
11
+ route_klass = message.destination
12
+
13
+ if route_klass.nil?
14
+ Hay.logger.error "Unknown route for task #{message.destination}"
15
+ raise "Unknown route for task #{message.destination}"
16
+ end
17
+
18
+ route = route_klass.new(@agent)
19
+
20
+ route.push(message)
21
+ end
22
+ end
23
+ end
24
+
25
+
data/lib/hay/routes.rb ADDED
@@ -0,0 +1,24 @@
1
+ require 'punchout'
2
+ require 'punchout/matcher/equal'
3
+
4
+ module Hay
5
+ module Routes
6
+ extend Punchout::Punchable
7
+
8
+ def self.register(route)
9
+ route.tasks.each do |task|
10
+ matchable = Punchout::Matcher::Equal.new(task.task_name).punches(route)
11
+ puncher.add(matchable)
12
+ end
13
+ end
14
+
15
+ def self.for_task(task)
16
+ punch(task.task_name)
17
+ end
18
+
19
+ def self.for_name(name)
20
+ punch(name)
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,35 @@
1
+ require 'delegate'
2
+
3
+ module Hay
4
+ module Task
5
+ class Decorator < SimpleDelegator
6
+
7
+
8
+ def initialize(obj)
9
+ super
10
+ end
11
+
12
+ attr_writer :flow
13
+
14
+ def flow
15
+ @flow ||= Hay::Task::Flow.new
16
+ end
17
+
18
+ def dehydrate
19
+ {
20
+ "name" => task_name,
21
+ "task" => super,
22
+ "flow" => flow.dehydrate
23
+ }
24
+ end
25
+
26
+ def process(dispatcher)
27
+ resulter = Hay::Task::Resulter.new(flow, dispatcher)
28
+ super(resulter)
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ require 'hay/task/flow'
35
+ require 'hay/task/resulter'
@@ -0,0 +1,10 @@
1
+ require 'hay/task/exception'
2
+
3
+ module Hay
4
+ module Task
5
+ class Exception < StandardError
6
+ class TransientException < Hay::Task::Exception
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,16 @@
1
+ module Hay
2
+ module Task
3
+ class Exception < StandardError
4
+ class UnknownTemplateError < StandardError
5
+ def initialize(template_name)
6
+ @template_name = template_name
7
+ end
8
+
9
+ def message
10
+ "Failed to find template #{@template_name}"
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,11 @@
1
+ module Hay
2
+ module Task
3
+ class Exception < StandardError
4
+ def initialize(cause)
5
+ @cause = cause
6
+ end
7
+
8
+ attr_accessor :cause
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,41 @@
1
+ require 'hay'
2
+
3
+ require 'hay/task/template'
4
+
5
+ module Hay
6
+ module Task
7
+ class Flow
8
+ def initialize(list = [])
9
+ @tasks = list || []
10
+ unless @tasks.kind_of?(Array)
11
+ raise "This has to be an array, dude!"
12
+ end
13
+ end
14
+
15
+ def push(tasks)
16
+ tasks = Array(tasks)
17
+
18
+ @tasks += tasks
19
+ end
20
+
21
+ def dehydrate
22
+ @tasks.map do |n|
23
+ if n.kind_of?(Hash)
24
+ Hay.logger.debug("Not dehydrating an already dehydrated #{n.inspect}")
25
+ n
26
+ else
27
+ Hay.logger.debug("Dehydrating #{n.inspect}")
28
+ n.dehydrate
29
+ end
30
+ end
31
+ end
32
+
33
+ def inflate
34
+ @tasks.map do |params|
35
+ Hay.logger.debug("Inflating #{params.inspect}")
36
+ Hay::Task::Template.new(params)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,21 @@
1
+ module Hay
2
+ module Task
3
+ class Factory
4
+ module Registry
5
+ @@factories = {}
6
+
7
+ def self.register(task_class)
8
+ @@factories[task_class.task_name] = Hay::Task::Factory.new(task_class)
9
+ end
10
+
11
+ def self.factory_by_task_class(task_class)
12
+ @@factories[task_class.task_name]
13
+ end
14
+
15
+ def self.factory_by_task_name(task_name)
16
+ @@factories[task_name]
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ require 'hay/task/flow'
2
+
3
+ module Hay
4
+ module Task
5
+ class Hydrator
6
+ def initialize(hash)
7
+ @hash = hash
8
+ end
9
+
10
+ def hydrate
11
+ task_class = Hay::Tasks.for_name(@hash['name'])
12
+ if task_class.nil?
13
+ raise "No task for name #{@hash['name']}"
14
+ end
15
+ task = task_class.new(@hash['task']).to_hay
16
+ task.flow = Hay::Task::Flow.new(@hash['flow'])
17
+ task
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ require 'hay'
2
+
3
+ require 'punchout/matcher/equal'
4
+
5
+ module Hay
6
+ module Task
7
+ module Hydrators
8
+ extend Punchout::Punchable
9
+
10
+ def self.register(task, hydrator)
11
+ Hay.logger.info "Registering hydrator #{task.task_name} for #{hydrator}"
12
+ matchable = Punchout::Matcher::Equal.new(task.task_name).punches(hydrator)
13
+ puncher.add(matchable)
14
+ end
15
+
16
+ def self.for(params)
17
+ if params['name'].nil?
18
+ raise "No name in parameter list: #{params.inspect}"
19
+ end
20
+ hydrator = punch(params['name'])
21
+ if hydrator.nil?
22
+ raise "No hydrator for task name #{params["name"]}: #{self.puncher.inspect}"
23
+ end
24
+ hydrator.new(params)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,16 @@
1
+ #require 'hay/task/factory'
2
+
3
+ module Hay
4
+ module Task
5
+ ##
6
+ # A registry for any tasks which the system knows how to create.
7
+ #
8
+ module Registry
9
+ def self.register(task)
10
+ Hay.logger.info "Registering #{task} for #{task.task_name}"
11
+
12
+ #Hay::Task::Factory::Registry.register(task)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ require 'hay/task/hydrators'
2
+ require 'hay/task/resolvers'
3
+
4
+ module Hay
5
+ module Task
6
+ module Resolver
7
+ class Hash
8
+ def initialize(hash)
9
+ @hash = hash
10
+ end
11
+
12
+ def build
13
+ Hay::Task::Hydrators.for(@hash).hydrate
14
+ end
15
+ Hay::Task::Resolvers.register(::Hash, self)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ module Hay
2
+ module Task
3
+ module Resolver
4
+ module Registry
5
+ def self.resolver_for(task_class)
6
+ Hay::Task::Resolvers.punch(task_class)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ require 'hay/task/decorator'
2
+
3
+ module Hay
4
+ module Task
5
+ module Resolver
6
+ class Task
7
+ def initialize(task)
8
+ @task = task
9
+ end
10
+
11
+ def build
12
+ @task
13
+ end
14
+ Hay::Task::Resolvers.register(Hay::Task::Decorator, self)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ require 'hay'
2
+
3
+ require 'hay/task/exception/unknown_template_error'
4
+
5
+ module Hay
6
+ module Task
7
+ module Resolver
8
+ def self.new(params)
9
+ resolver_class = Hay::Task::Resolvers.punch(params)
10
+ if resolver_class.nil?
11
+ raise Hay::Task::Exception::UnknownTemplateError.new("No resolver for #{params.class}")
12
+ end
13
+ resolver_class.new(params).build
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,20 @@
1
+ require 'punchout'
2
+ require 'punchout/matcher/ancestry'
3
+
4
+ module Hay
5
+ module Task
6
+ module Resolvers
7
+ extend Punchout::Punchable
8
+
9
+ def self.register(type, resolver)
10
+ Hay.logger.info "Registering resolver #{type} for #{resolver}"
11
+ matchable = Punchout::Matcher::Ancestry.new(type).punches(resolver)
12
+ puncher.add(matchable)
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ require 'hay/task/resolver/hash'
19
+ require 'hay/task/resolver/task'
20
+