cascadence 0.1.2 → 0.2.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.
@@ -0,0 +1 @@
1
+ fasdfa\n=
@@ -0,0 +1,26 @@
1
+ module Amazon
2
+ class MadeiraFlow < ::Cascadence::Flow
3
+ cascading_order :step1, :step2, :step3
4
+
5
+ def initialize(state)
6
+ self.state = state || "initialized"
7
+ puts state
8
+ end
9
+
10
+ def step1
11
+ self.state += "1"
12
+ puts state
13
+ end
14
+
15
+ def step2
16
+ self.state += "2"
17
+ puts state
18
+ end
19
+
20
+ def step3
21
+ self.state += "3"
22
+ puts state
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1 @@
1
+ asdf
@@ -0,0 +1,2 @@
1
+ module Amazon
2
+ end
@@ -0,0 +1 @@
1
+ (defn dogwood [ca] (ca) )
@@ -0,0 +1 @@
1
+ describe Faggot do; end
@@ -0,0 +1,3 @@
1
+ require File.join(File.dirname(__FILE__), "amazon", "madeira_flow")
2
+
3
+ Cascadence.config.zero_state_generator = lambda { "zerostate" }
@@ -0,0 +1 @@
1
+ asdfasdfasdfasdf
@@ -0,0 +1 @@
1
+ dfasdf
@@ -0,0 +1 @@
1
+ fajsdf
@@ -0,0 +1 @@
1
+ dfasdf
@@ -0,0 +1 @@
1
+ describe Faggot do; end
data/lib/cascadence.rb CHANGED
@@ -1,7 +1,21 @@
1
-
1
+ require "thor"
2
+ require "active_support/core_ext/string"
3
+ require "active_support/core_ext/module"
4
+ require "singleton"
2
5
  module Cascadence
3
6
  autoload :Stateful, File.join( File.dirname(__FILE__), "cascadence", "stateful" )
4
7
  autoload :ClassMethods, File.join( File.dirname(__FILE__), "cascadence", "class_methods" )
5
8
  autoload :Flow, File.join( File.dirname(__FILE__), "cascadence", "flow" )
6
9
  autoload :Helper, File.join( File.dirname(__FILE__), "cascadence", "helper")
10
+ autoload :Commander, File.join( File.dirname(__FILE__), "cascadence", "commander")
11
+ autoload :Runner, File.join( File.dirname(__FILE__), "cascadence", "runner")
12
+ autoload :Config, File.join( File.dirname(__FILE__), "cascadence", "config")
13
+ autoload :Task, File.join( File.dirname(__FILE__), "cascadence", "task")
14
+ def self.config
15
+ Config.instance
16
+ end
17
+
18
+ def self.runner
19
+ Runner.instance
20
+ end
7
21
  end
@@ -0,0 +1,75 @@
1
+ module Cascadence
2
+ class Commander < Thor
3
+
4
+ desc "version", "Not implemented yet. That's right, the command that tells you what version of cascadence you're running has not been implemented yet."
5
+ def version
6
+ puts "El Psy Congroo"
7
+ end
8
+
9
+ desc "flow", "Runs the flow specified in the given file. If given a directory, runs all the flows in the directory."
10
+ def flow(filepath=Dir.pwd)
11
+ files = _get_files_from_filepath _absolutize_filepath filepath
12
+ _setup_environment_from_filepath!(filepath)
13
+ tasks = files.map { |file| _get_task_from_file file }
14
+ _run_tasks tasks
15
+ end
16
+
17
+ private
18
+
19
+ def _run_tasks(tasks)
20
+ Cascadence.runner.run_tasks tasks
21
+ end
22
+
23
+ def _absolutize_filepath(filepath)
24
+ return filepath if filepath =~ /^\//
25
+ return File.expand_path(filepath) if filepath =~ /^~/
26
+ return File.join(Dir.pwd, filepath)
27
+ end
28
+
29
+ def _get_files_from_filepath(filepath)
30
+ return [filepath] if _flow_file? filepath
31
+ return [] unless File.exists? filepath
32
+ Dir[File.join(filepath, "*")].map { |file_or_dir| _get_files_from_filepath file_or_dir }.flatten
33
+ end
34
+
35
+ def _flow_file?(filepath)
36
+ (filepath =~ /_flow\.rb$/) && File.file?(filepath)
37
+ end
38
+
39
+ def _setup_environment_from_filepath!(filepath)
40
+ require _find_flow_helper_from_filepath filepath
41
+ end
42
+
43
+ def _find_flow_helper_from_filepath( filepath )
44
+ _find_flow_helper_from_filepath File.expand_path("..", filepath) unless File.directory? filepath
45
+ throw :NoFlowHelperFound if filepath == "/"
46
+ Dir[File.join(filepath, "*")].select { |file| _flow_helper? file }.first || _find_flow_helper_from_filepath( File.expand_path("..", filepath) )
47
+ end
48
+
49
+ def _flow_helper?(filepath)
50
+ (filepath =~ /\/flow_helper\.rb$/) && File.file?(filepath)
51
+ end
52
+
53
+ def _get_task_from_file(file)
54
+ flow = _get_flow_from_file file
55
+ Cascadence::Task.new(_get_zero_state_generator_from_flow flow) do |state=nil|
56
+ flow.new(state).run_states
57
+ end
58
+ end
59
+
60
+ def _get_zero_state_generator_from_flow(flow)
61
+ return flow.zero_state_generator if flow.respond_to? :zero_state_generator
62
+ return Cascadence.config.zero_state_generator if flow == Object
63
+ _get_zero_state_generator_from_flow(flow.parent)
64
+ end
65
+
66
+ def _get_flow_from_file(file)
67
+ Cascadence::Flow.subclasses.select { |subclass| _reasonably_matched?(subclass.to_s, file.chomp(".rb")) }.first
68
+ end
69
+
70
+ def _reasonably_matched?(str1, str2)
71
+ !(str2.to_s.gsub(/^\/?/, "/") =~ Regexp.new("\/" + str1.to_s.split("::").map(&:underscore).join("/") + "$")).nil?
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,12 @@
1
+ module Cascadence
2
+ class Config
3
+ include Singleton
4
+ attr_accessor :parallel, :zero_state_generator, :max_thread_count
5
+
6
+ def initialize
7
+ @parallel = false
8
+ @zero_state_generator = lambda {}
9
+ @max_thread_count = 5
10
+ end
11
+ end
12
+ end
@@ -6,7 +6,11 @@ module Cascadence
6
6
  include Stateful
7
7
  attr_accessor :state
8
8
 
9
+ def self.subclasses
10
+ @@subclasses ||= []
11
+ end
9
12
  def self.inherited(child)
13
+ Flow.subclasses.push child
10
14
  if child.superclass.respond_to? :cascadence_order
11
15
  order = child.superclass.cascadence_order
12
16
  child.cascading_order *order
@@ -0,0 +1,62 @@
1
+ module Cascadence
2
+ class Runner
3
+ include Singleton
4
+
5
+ def run_tasks(tasks)
6
+ if Cascadence.config.parallel
7
+ _run_parallel tasks
8
+ else
9
+ _run_sequential tasks
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ # def _run_parallel(tasks)
16
+ # threads = []
17
+ # puts "Attempting to run with #{tasks.count} tasks"
18
+ # tasks.each do |task|
19
+ # thread = Thread.new do
20
+ # puts "Spinning up thread number #{threads.count}"
21
+ # task.call
22
+ # end
23
+ # puts "Pushing thread number #{threads.count} to thread pool"
24
+ # threads << thread
25
+ # sleep 0.5
26
+ # end
27
+ # while threads.inject(false) { |finished, thread| finished || thread.alive? }
28
+ # sleep 0.5
29
+ # end
30
+ # end
31
+
32
+ def _run_parallel(tasks, threads=[])
33
+ return if tasks.empty? && threads.empty?
34
+ package = _maybe_spin_up_thread(tasks, threads)
35
+ new_tasks = package.first
36
+ new_threads = package.last
37
+ _run_parallel new_tasks, new_threads
38
+ end
39
+
40
+ def _maybe_spin_up_thread(tasks, threads=[])
41
+ if threads.count > Cascadence.config.max_thread_count
42
+ new_threads = threads
43
+ new_tasks = tasks
44
+ else
45
+ new_threads = _spin_up_task(tasks.pop, threads)
46
+ new_tasks = tasks
47
+ end
48
+ sleep 0.5
49
+ return [new_tasks, new_threads.select(&:alive?)]
50
+ end
51
+
52
+ def _spin_up_task(task, threads=[])
53
+ puts "Spinning up thread no.#{threads.count} out of #{Cascadence.config.max_thread_count}"
54
+ thread = Thread.new { task.call } unless task.nil?
55
+ threads.push thread unless thread.nil?
56
+ end
57
+
58
+ def _run_sequential(tasks)
59
+ tasks.map(&:call).map(&:state)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,14 @@
1
+ module Cascadence
2
+ class Task
3
+ def initialize(zero_state_generator=nil, &block)
4
+ @block = block
5
+ @zstate_gen = zero_state_generator
6
+ @zstate_gen ||= Cascadence.config.zero_state_generator
7
+ end
8
+
9
+ def call
10
+ @block.call @zstate_gen.call
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,122 @@
1
+ require 'spec_helper'
2
+
3
+ describe Cascadence::Flow do
4
+ let(:amazon) do
5
+ Class.new(Cascadence::Flow) do
6
+ cascading_order :step1, :step2, :step3, :stepcrap
7
+ def initialize
8
+ self.state = "initialize"
9
+ end
10
+
11
+ def step1
12
+ self.state += "1"
13
+ end
14
+
15
+ def step2
16
+ self.state += "2"
17
+ end
18
+
19
+ def step3
20
+ self.state += "3"
21
+ end
22
+
23
+ def stepcrap
24
+ self.state += "crap"
25
+ end
26
+ end
27
+ end
28
+ context "preemptivization" do
29
+ let(:amazon_zero) do
30
+ Class.new(amazon) do
31
+ merge_before :step1
32
+ cascading_order :step0
33
+
34
+ def step0
35
+ self.state += "0"
36
+ end
37
+ end
38
+ end
39
+ describe "#cascadence_order" do
40
+ context "child" do
41
+ subject { amazon_zero.cascadence_order }
42
+
43
+ it "should be a continuation of the parent" do
44
+ pending "Not going to worry about this unless this is actually needed"
45
+ should eq [:step0, :step1, :step2, :step3, :stepcrap]
46
+ end
47
+ end
48
+ context "parent" do
49
+ subject { amazon.cascadence_order }
50
+
51
+ it "should be as expected from the declaration" do
52
+ should eq [:step1, :step2, :step3, :stepcrap]
53
+ end
54
+ end
55
+ end
56
+ describe "#run_states" do
57
+ context "child" do
58
+ subject { amazon_zero.new.run_states.state }
59
+
60
+ it "should give the expected state value" do
61
+ pending "Not going to worry about this unless this is actually needed"
62
+ should eq "initialize0123crap"
63
+ end
64
+ end
65
+ context "parent" do
66
+ subject {amazon.new.run_states.state }
67
+ it "should give the expected parent state value" do
68
+ should eq "initialize123crap"
69
+ end
70
+ end
71
+ end
72
+ end
73
+ context "continuation" do
74
+ let(:amazon_prime) do
75
+ Class.new(amazon) do
76
+ fork_after :step3
77
+ cascading_order :step4, :step5
78
+
79
+ def step4
80
+ self.state += "4"
81
+ end
82
+
83
+ def step5
84
+ self.state += "5"
85
+ end
86
+ end
87
+ end
88
+
89
+ describe "#cascadence_order" do
90
+ context "child" do
91
+ subject { amazon_prime.cascadence_order }
92
+
93
+ it "should be a continuation of the parent" do
94
+ should eq [:step1, :step2, :step3, :step4, :step5]
95
+ end
96
+ end
97
+ context "parent" do
98
+ subject { amazon.cascadence_order }
99
+
100
+ it "should be as expected from the declaration" do
101
+ should eq [:step1, :step2, :step3, :stepcrap]
102
+ end
103
+ end
104
+ end
105
+
106
+ describe "#run_states" do
107
+ context "child" do
108
+ subject { amazon_prime.new.run_states.state }
109
+
110
+ it "should give the expected state value" do
111
+ should eq "initialize12345"
112
+ end
113
+ end
114
+ context "parent" do
115
+ subject {amazon.new.run_states.state }
116
+ it "should give the expected parent state value" do
117
+ should eq "initialize123crap"
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,184 @@
1
+ require "spec_helper"
2
+
3
+
4
+ describe Cascadence::Commander do
5
+ let(:lolcat) { Cascadence::Commander.new }
6
+ context "public api" do
7
+ describe "#flow" do
8
+ let(:result) { lolcat.flow File.join(RSpec::FixturePath, "amazon", "madeira_flow.rb") }
9
+ it "should run the flow stated" do
10
+ result.should eq ["initialized123"]
11
+ end
12
+ end
13
+ end
14
+ context "private" do
15
+ describe "#_get_zero_state_generator_from_flow" do
16
+ module GetZero
17
+ def self.zero_state_generator
18
+ lambda { "get_zero" }
19
+ end
20
+ class Fagbar < Cascadence::Flow
21
+ class HeyzapFlow < ::Cascadence::Flow
22
+ class CrossFlow
23
+ class WeHaveToGoDeeper
24
+ def self.zero_state_generator
25
+ lambda { "we_have_to_go_deeper" }
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ it "should properly give me parents where applicable" do
33
+ GetZero::Fagbar::HeyzapFlow::CrossFlow::WeHaveToGoDeeper.parent.should eq GetZero::Fagbar::HeyzapFlow::CrossFlow
34
+ end
35
+ it "should give me nil for the outer level" do
36
+ GetZero.parent.should == Object
37
+ end
38
+ let(:result) { lolcat.send "_get_zero_state_generator_from_flow", @flow }
39
+ context "warpspeed" do
40
+ before :each do
41
+ @flow = GetZero::Fagbar::HeyzapFlow::CrossFlow
42
+ end
43
+ it "should get me the first zero_state_generator" do
44
+ result.call.should eq "get_zero"
45
+ end
46
+ end
47
+ context "inception" do
48
+ before :each do
49
+ @flow = GetZero::Fagbar::HeyzapFlow::CrossFlow::WeHaveToGoDeeper
50
+ end
51
+ it "should get the closest zero state generator" do
52
+ result.call.should eq "we_have_to_go_deeper"
53
+ end
54
+ end
55
+ end
56
+ describe "#_absolutize_filepath" do
57
+ let(:path) { lolcat.send "_absolutize_filepath", @input }
58
+ let(:result) { path.should eq @expected }
59
+ context "standard usage" do
60
+ before :each do
61
+ @input = "dog"
62
+ @expected = File.join Dir.pwd, @input
63
+ end
64
+ it( "should give me an absolute path to the file regardless of existence") { result }
65
+ end
66
+ context "~" do
67
+ before :each do
68
+ @input = "~/dogfucker"
69
+ @expected = File.join File.expand_path("~"), "dogfucker"
70
+ end
71
+ it( "should expand the tilde to the absolute path") { result }
72
+ end
73
+ context "absolute path" do
74
+ before :each do
75
+ @input = "/home/shinka/something"
76
+ @expected = @input
77
+ end
78
+ it("should not touch the input if it is already absolute") { result }
79
+ end
80
+ end
81
+ describe "#_reasonably_matched?" do
82
+ let(:match) { lambda { |s1, s2| lolcat.send "_reasonably_matched?", s1, s2 } }
83
+ context "true" do
84
+ before :each do
85
+ @expectations = {
86
+ "Dog::Cat::Bat" => "/dog/cat/bat",
87
+ "AssFuck::Shot" => "/ass_fuck/shot",
88
+ "Dicker::BatMan::Robin" => "apples/oranges/dicker/bat_man/robin",
89
+ "Snot" => "/asdf/asdf/asdf/ff/snot"
90
+ }
91
+ end
92
+ it "should be a reasonable match" do
93
+ @expectations.each { |key, val| match.call(key,val).should be_true }
94
+ end
95
+ end
96
+ context "false" do
97
+ before :each do
98
+ @expectations = {
99
+ "Dog::Cat::Bat" => "/fdasf/dog/cat/rat",
100
+ "" => "/anything/really" ,
101
+ "Dicker::AssMan" => "/fd/dicker/ass_man/something"
102
+ }
103
+ end
104
+ it "should not be reasonable matches" do
105
+ @expectations.each { |key,val| match.call(key,val).should_not be_true }
106
+ end
107
+ end
108
+ end
109
+ describe "#_get_flow_from_file" do
110
+ let(:flow) { lolcat.send "_get_flow_from_file", @file }
111
+ let(:expected) { Amazon::MadeiraFlow }
112
+ before :each do
113
+ @file = File.join RSpec::FixturePath, "amazon", "madeira_flow.rb"
114
+ require @file
115
+ end
116
+ context "standard usage" do
117
+ it "should find the flow class in question" do
118
+ flow.should eq expected
119
+ end
120
+ end
121
+ describe "#_get_task_from_file" do
122
+ let(:task) { lolcat.send("_get_task_from_file", @file) }
123
+
124
+ it "should be a lambda" do
125
+ task.should respond_to :call
126
+ end
127
+
128
+ it "should run and give me the correct result" do
129
+ task.call.state.should eq "initialized123"
130
+ end
131
+ end
132
+ end
133
+ describe "#_find_flow_helper_from_filepath" do
134
+ let(:path) { lolcat.send "_find_flow_helper_from_filepath", @starting }
135
+ context "null case" do
136
+ before :each do
137
+ @starting = File.expand_path __FILE__
138
+ end
139
+ it "should throw an symbol as it cannot find the flow helper" do
140
+ expect { path }.to throw_symbol :NoFlowHelperFound
141
+ end
142
+ end
143
+ context "dumb case" do
144
+ before :each do
145
+ @starting = File.join RSpec::FixturePath, "flow_helper.rb"
146
+ @expected = @starting
147
+ end
148
+ it "should find it right away" do
149
+ path.should eq @expected
150
+ end
151
+ end
152
+ context "standard usage" do
153
+ before :each do
154
+ @starting = File.join RSpec::FixturePath, "nile", "white_nile"
155
+ @expected = File.join RSpec::FixturePath, "flow_helper.rb"
156
+ end
157
+
158
+ it "should find the expected flow helper in the fixture folder" do
159
+ path.should eq @expected
160
+ end
161
+ end
162
+ end
163
+ describe "#_get_files_from_filepath" do
164
+ context "standard usage" do
165
+ let(:files) { lolcat.send( "_get_files_from_filepath", File.join(RSpec::FixturePath) ) }
166
+ before :each do
167
+ @expected = Dir[File.join(RSpec::FixturePath, "*_flow.rb")].map { |f| f }
168
+ @expected += Dir[File.join(RSpec::FixturePath,"**", "*_flow.rb")].map { |f| f }
169
+ @expected += Dir[File.join(RSpec::FixturePath,"**", "**", "*_flow.rb")].map { |f| f }
170
+ @expected.uniq!
171
+ end
172
+
173
+ it "should fetch all the files that are flow rubies" do
174
+ files.sort.should eq @expected.sort
175
+ end
176
+ end
177
+ context "null usage" do
178
+ it "should out an empty array if the path doesn't exist" do
179
+ lolcat.send("_get_files_from_filepath", "nigstack").should be_empty
180
+ end
181
+ end
182
+ end
183
+ end
184
+ end