cascadence 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +36 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +23 -0
- data/Rakefile +36 -0
- data/VERSION +1 -0
- data/cascadence.gemspec +111 -0
- data/coverage/.last_run.json +5 -0
- data/coverage/.resultset.json +588 -0
- data/coverage/assets/0.7.1/application.css +1110 -0
- data/coverage/assets/0.7.1/application.js +626 -0
- data/coverage/assets/0.7.1/fancybox/blank.gif +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_close.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_loading.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_nav_left.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_nav_right.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_e.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_n.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_ne.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_nw.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_s.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_se.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_sw.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_shadow_w.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_title_left.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_title_main.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_title_over.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancy_title_right.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancybox-x.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancybox-y.png +0 -0
- data/coverage/assets/0.7.1/fancybox/fancybox.png +0 -0
- data/coverage/assets/0.7.1/favicon_green.png +0 -0
- data/coverage/assets/0.7.1/favicon_red.png +0 -0
- data/coverage/assets/0.7.1/favicon_yellow.png +0 -0
- data/coverage/assets/0.7.1/loading.gif +0 -0
- data/coverage/assets/0.7.1/magnify.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/coverage/assets/0.7.1/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/coverage/index.html +3702 -0
- data/lib/cascadence/class_methods.rb +39 -0
- data/lib/cascadence/flow.rb +17 -0
- data/lib/cascadence/helper.rb +21 -0
- data/lib/cascadence/stateful.rb +81 -0
- data/lib/cascadence.rb +7 -0
- data/spec/cascadence/class_methods_spec.rb +128 -0
- data/spec/cascadence/flow_spec.rb +64 -0
- data/spec/cascadence/fork_merge_spec.rb +86 -0
- data/spec/cascadence/helper_spec.rb +106 -0
- data/spec/cascadence/stateful_spec.rb +136 -0
- data/spec/cascadence_spec.rb +13 -0
- data/spec/spec_helper.rb +4 -0
- metadata +178 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
module Cascadence
|
3
|
+
|
4
|
+
module ClassMethods
|
5
|
+
# Yes, I realize this is confusing
|
6
|
+
# I'm sorry for code-gulfing
|
7
|
+
# TODO: Write this class so we don't depend so heavily
|
8
|
+
# on recusion and "lazy evaluation" to get the ordering.
|
9
|
+
# This is probably 100% necessary if this project were
|
10
|
+
# ever to get big and require junk
|
11
|
+
def cascadence_order
|
12
|
+
@cascadence_order ||= []
|
13
|
+
@forked_position ||= []
|
14
|
+
@merge_position ||= []
|
15
|
+
unless @cascadence_order.nil?
|
16
|
+
Helper.generate_tributary(@cascadence_order.reverse, @forked_position.clone, @merge_position.clone)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def cascading_order( *order )
|
21
|
+
@cascadence_order ||= []
|
22
|
+
@cascadence_order << order
|
23
|
+
end
|
24
|
+
|
25
|
+
def fork_after( location )
|
26
|
+
@forked_position ||= []
|
27
|
+
index = cascadence_order.index location
|
28
|
+
@forked_position << (index + 1)
|
29
|
+
end
|
30
|
+
|
31
|
+
def merge_before( location )
|
32
|
+
@merge_position ||= []
|
33
|
+
index = cascadence_order.index location
|
34
|
+
@merge_position << (index - 1)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
module Cascadence
|
3
|
+
|
4
|
+
# A simple implementation of stateful
|
5
|
+
class Flow
|
6
|
+
include Stateful
|
7
|
+
attr_accessor :state
|
8
|
+
|
9
|
+
def self.inherited(child)
|
10
|
+
if child.superclass.respond_to? :cascadence_order
|
11
|
+
order = child.superclass.cascadence_order
|
12
|
+
child.cascading_order *order
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Cascadence
|
2
|
+
module Helper
|
3
|
+
# see the specs for what these guys do
|
4
|
+
def self.generate_tributary( arrays, starts=[], finish=[] )
|
5
|
+
|
6
|
+
if starts.empty? || arrays.count == 1
|
7
|
+
return arrays.reverse.flatten
|
8
|
+
end
|
9
|
+
generate_tributary arrays.push(replace_in_part(arrays.pop, arrays.pop, starts.pop, finish.pop) ), starts, finish
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.replace_in_part(original, chunk, start, finish=nil)
|
13
|
+
return chunk if original.nil? || original.empty?
|
14
|
+
throw :OutOfRange if start >= original.count
|
15
|
+
result = original.clone
|
16
|
+
result[start..(finish||-1)] = chunk
|
17
|
+
return result
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
|
2
|
+
module Cascadence
|
3
|
+
|
4
|
+
module Stateful
|
5
|
+
|
6
|
+
def self.included( base )
|
7
|
+
base.extend ClassMethods
|
8
|
+
base.class_exec do
|
9
|
+
attr_reader :cascadence_position
|
10
|
+
end # class_exec
|
11
|
+
end
|
12
|
+
|
13
|
+
def run_states
|
14
|
+
run_until :end
|
15
|
+
end
|
16
|
+
|
17
|
+
def run_until( target=nil )
|
18
|
+
|
19
|
+
return run_next if target.nil? and !block_given?
|
20
|
+
|
21
|
+
if block_given?
|
22
|
+
while !_cascadence_end? and !yield(self)
|
23
|
+
run_next
|
24
|
+
end
|
25
|
+
return self
|
26
|
+
end
|
27
|
+
|
28
|
+
case target.class.to_s
|
29
|
+
when "String", "Symbol"
|
30
|
+
return run_until { |state| state.current_step_name.to_s == target.to_s }
|
31
|
+
when "Fixnum", "Integer"
|
32
|
+
return run_until { |state| state.cascadence_position == target }
|
33
|
+
else
|
34
|
+
throw "Bad input error." unless target.respond_to? :call
|
35
|
+
return run_until { |state| target.call state }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def run_next
|
40
|
+
_debug_helper
|
41
|
+
|
42
|
+
unless next_step_name.nil?
|
43
|
+
send next_step_name
|
44
|
+
_increment_cascadence
|
45
|
+
end
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
def current_step_name
|
50
|
+
return nil if cascadence_position.nil?
|
51
|
+
self.class.cascadence_order[cascadence_position]
|
52
|
+
end
|
53
|
+
|
54
|
+
def next_step_name
|
55
|
+
return self.class.cascadence_order.first if cascadence_position.nil?
|
56
|
+
self.class.cascadence_order[cascadence_position+1]
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def _cascadence_end?
|
62
|
+
return false if cascadence_position.nil?
|
63
|
+
cascadence_position >= self.class.cascadence_order.count - 1
|
64
|
+
end
|
65
|
+
|
66
|
+
def _increment_cascadence
|
67
|
+
if @cascadence_position.nil?
|
68
|
+
@cascadence_position = 0
|
69
|
+
else
|
70
|
+
@cascadence_position += 1
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def _debug_helper
|
75
|
+
@debug_counter ||= 0
|
76
|
+
@debug_counter += 1
|
77
|
+
throw "Recursion Limit Reached! cascadence_position: #{cascadence_position} --> #{next_step_name}" if 100 < @debug_counter
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
data/lib/cascadence.rb
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
|
2
|
+
module Cascadence
|
3
|
+
autoload :Stateful, File.join( File.dirname(__FILE__), "cascadence", "stateful" )
|
4
|
+
autoload :ClassMethods, File.join( File.dirname(__FILE__), "cascadence", "class_methods" )
|
5
|
+
autoload :Flow, File.join( File.dirname(__FILE__), "cascadence", "flow" )
|
6
|
+
autoload :Helper, File.join( File.dirname(__FILE__), "cascadence", "helper")
|
7
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cascadence::ClassMethods do
|
4
|
+
|
5
|
+
let(:life) do
|
6
|
+
Class.new( Cascadence::Flow ) do
|
7
|
+
cascading_order :childhood, :teenage, :adulthood, :marriage, :mid_age, :old_age, :death
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
self.state = "created"
|
11
|
+
end
|
12
|
+
|
13
|
+
def childhood
|
14
|
+
self.state += "-happy"
|
15
|
+
end
|
16
|
+
|
17
|
+
def teenage
|
18
|
+
self.state += "-misunderstood"
|
19
|
+
end
|
20
|
+
|
21
|
+
def adulthood
|
22
|
+
self.state += "-responsible"
|
23
|
+
end
|
24
|
+
|
25
|
+
def marriage
|
26
|
+
self.state += "-busy"
|
27
|
+
end
|
28
|
+
|
29
|
+
def mid_age
|
30
|
+
self.state += "-content"
|
31
|
+
end
|
32
|
+
|
33
|
+
def old_age
|
34
|
+
self.state += "-tired"
|
35
|
+
end
|
36
|
+
|
37
|
+
def death
|
38
|
+
self.state += "-rip"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "position" do
|
44
|
+
|
45
|
+
it "should give me the correct numerical value for the index command" do
|
46
|
+
life.cascadence_order.index(:teenage).should eq 1
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "inheritance" do
|
51
|
+
let(:japanese) { Class.new(life) }
|
52
|
+
|
53
|
+
describe "defaults" do
|
54
|
+
|
55
|
+
describe "#cascadence_order" do
|
56
|
+
subject { japanese.cascadence_order }
|
57
|
+
|
58
|
+
it "should be inherited from the parent cascadence order" do
|
59
|
+
should eq life.cascadence_order
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "#run_states" do
|
64
|
+
subject { japanese.new.run_states.state }
|
65
|
+
|
66
|
+
it "should match exactly the states as run by the parent" do
|
67
|
+
should eq life.new.run_states.state
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "difference" do
|
74
|
+
|
75
|
+
before :each do
|
76
|
+
japanese.class_exec do
|
77
|
+
def loli
|
78
|
+
self.state += "-kawaii"
|
79
|
+
end
|
80
|
+
|
81
|
+
def schoolgirl
|
82
|
+
self.state += "-chikan"
|
83
|
+
end
|
84
|
+
|
85
|
+
def ol
|
86
|
+
self.state += "-alcoholic"
|
87
|
+
end
|
88
|
+
|
89
|
+
def settle
|
90
|
+
self.state += "-ntr"
|
91
|
+
end
|
92
|
+
|
93
|
+
def mid_age
|
94
|
+
self.state += "-depressed"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "position" do
|
100
|
+
it "should have the correct position" do
|
101
|
+
japanese.fork_after :childhood
|
102
|
+
japanese.merge_before :mid_age
|
103
|
+
japanese.cascadence_order.should eq [:childhood, :teenage, :adulthood, :marriage, :mid_age, :old_age, :death]
|
104
|
+
japanese.cascading_order :loli, :schoolgirl, :ol, :settle
|
105
|
+
japanese.cascadence_order.should eq [:childhood, :loli, :schoolgirl, :ol, :settle, :mid_age, :old_age, :death]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "results" do
|
110
|
+
before :each do
|
111
|
+
japanese.fork_after :childhood
|
112
|
+
japanese.merge_before :mid_age
|
113
|
+
japanese.cascading_order :loli, :schoolgirl, :ol, :settle
|
114
|
+
end
|
115
|
+
it "should have a different cascadence order than the parent class" do
|
116
|
+
life.cascadence_order.should_not eq japanese.cascadence_order
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should result in a different terminal state when the states are run" do
|
120
|
+
life.new.run_states.state.should_not eq japanese.new.run_states.state
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class FlowTest < Cascadence::Flow
|
4
|
+
|
5
|
+
cascading_order :step1, :step2, :step3, :step4
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
self.state = "initialized"
|
9
|
+
end
|
10
|
+
|
11
|
+
def step1
|
12
|
+
self.state += "-step1"
|
13
|
+
end
|
14
|
+
|
15
|
+
def step2
|
16
|
+
self.state += "-step2"
|
17
|
+
end
|
18
|
+
|
19
|
+
def step3
|
20
|
+
self.state += "-step3"
|
21
|
+
end
|
22
|
+
|
23
|
+
def step4
|
24
|
+
self.state += "-step4"
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
describe Cascadence::Flow do
|
30
|
+
|
31
|
+
before :each do
|
32
|
+
@flow = FlowTest.new
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "sanity" do
|
36
|
+
|
37
|
+
it "should be an instance of flowtest" do
|
38
|
+
@flow.class.should eq FlowTest
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should respond to state" do
|
42
|
+
@flow.should respond_to :state
|
43
|
+
@flow.should respond_to :state=
|
44
|
+
@flow.state.should eq "initialized"
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should be an instance of cascadence::flow" do
|
48
|
+
FlowTest.superclass.should eq Cascadence::Flow
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "run states" do
|
54
|
+
|
55
|
+
before(:each) { @expected = "initialized-step1-step2-step3-step4" }
|
56
|
+
let(:actual) { @flow.run_states }
|
57
|
+
|
58
|
+
it "should run all four states in the specified cascading order" do
|
59
|
+
actual.state.should eq @expected
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cascadence::Flow do
|
4
|
+
let(:euphrates) do
|
5
|
+
Class.new( Cascadence::Flow ) do
|
6
|
+
cascading_order :eden, :babylon, :gulf
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
self.state = "created"
|
10
|
+
end
|
11
|
+
|
12
|
+
def eden
|
13
|
+
self.state += "-innocence"
|
14
|
+
end
|
15
|
+
|
16
|
+
def babylon
|
17
|
+
self.state += "-prosperity"
|
18
|
+
end
|
19
|
+
|
20
|
+
def gulf
|
21
|
+
self.state += "-downfall"
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
let(:tigris) do
|
28
|
+
Class.new( euphrates ) do
|
29
|
+
fork_after :eden
|
30
|
+
merge_before :gulf
|
31
|
+
cascading_order :sumer, :israel
|
32
|
+
def sumer
|
33
|
+
self.state += "-discovery"
|
34
|
+
end
|
35
|
+
|
36
|
+
def israel
|
37
|
+
self.state += "-arrogance"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "#cascadence_order" do
|
43
|
+
|
44
|
+
context "parent" do
|
45
|
+
subject { euphrates.cascadence_order }
|
46
|
+
|
47
|
+
it "should remain unchanged from what it was" do
|
48
|
+
should eq [:eden, :babylon, :gulf]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "child" do
|
53
|
+
subject { tigris.cascadence_order }
|
54
|
+
|
55
|
+
it "should have been forked from the parent cascadence order" do
|
56
|
+
should eq [:eden, :sumer, :israel, :gulf]
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#run_state" do
|
63
|
+
|
64
|
+
describe "parent" do
|
65
|
+
subject { euphrates.new.run_states.state }
|
66
|
+
|
67
|
+
it "should generate the expected state without regard to forks" do
|
68
|
+
should eq "created-innocence-prosperity-downfall"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "child" do
|
73
|
+
subject { tigris.new.run_states.state }
|
74
|
+
|
75
|
+
it "should have the right states to run" do
|
76
|
+
tigris.cascadence_order.should eq [:eden, :sumer, :israel, :gulf]
|
77
|
+
tigris.new.run_states.state.should eq "created-innocence-discovery-arrogance-downfall"
|
78
|
+
end
|
79
|
+
it "should generate the expected state after succesful forking from the parent" do
|
80
|
+
should eq "created-innocence-discovery-arrogance-downfall"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cascadence::Helper do
|
4
|
+
let(:api) { Cascadence::Helper }
|
5
|
+
|
6
|
+
describe "#generate_tributary" do
|
7
|
+
context "standard usage" do
|
8
|
+
before :each do
|
9
|
+
@arrays = [
|
10
|
+
["o","t"] ,
|
11
|
+
["a","g"] ,
|
12
|
+
["f","b","c","g"]
|
13
|
+
]
|
14
|
+
@starts = [1]
|
15
|
+
@finishes = [2]
|
16
|
+
@expected = ["f","a","g","g","o","t"]
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should reduce the given array to the expected array" do
|
20
|
+
api.generate_tributary(@arrays, @starts, @finishes).should eq @expected
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should work with simpler arrays also" do
|
24
|
+
arrays = [
|
25
|
+
['a','g','g','o'] ,
|
26
|
+
['f','b','b','b','t']
|
27
|
+
]
|
28
|
+
start = [1]
|
29
|
+
merge = [3]
|
30
|
+
api.generate_tributary(arrays, start, merge).should eq @expected
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "weird input" do
|
35
|
+
before :each do
|
36
|
+
@arrays = [
|
37
|
+
["o","t"] ,
|
38
|
+
["a","g"] ,
|
39
|
+
["f","b","c","g"]
|
40
|
+
]
|
41
|
+
@starts = [1]
|
42
|
+
@finishes = [2]
|
43
|
+
@expected = ["f","a","g","g","o","t"]
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should return the array as is" do
|
47
|
+
api.generate_tributary([[1,2,3,4]]).should eq [1,2,3,4]
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should entirely ignore merge points if no fork points were specified" do
|
51
|
+
api.generate_tributary(@arrays, [1], [23,234,23,23,3,2]).should eq @expected
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should entirely replace to the end if no merge points were specified" do
|
55
|
+
arrays = [
|
56
|
+
"I love eating food".split(" ") ,
|
57
|
+
"big throbbing ipad".split(" ") ,
|
58
|
+
"explicitive deleted".split(" ")
|
59
|
+
].reverse
|
60
|
+
api.generate_tributary(arrays, [4,2]).join(" ").should eq "I love big throbbing explicitive deleted"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "bad input" do
|
65
|
+
|
66
|
+
it "should do as much as possible and ignore the rest of the starts if the initial array isn't long enough" do
|
67
|
+
api.generate_tributary([[1,2,3,4,5], [10,2,3,4]], [5,4,3,1]).should eq [10,1,2,3,4,5]
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should throw an error if you attempt to start well after the array" do
|
71
|
+
expect do
|
72
|
+
api.generate_tributary([[1,2,3,4],[1,2,3]], [99])
|
73
|
+
end.to throw_symbol :OutOfRange
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#replace_in_part" do
|
80
|
+
|
81
|
+
it "should replace the specified chunk in a given array" do
|
82
|
+
original = "f a b t".split " "
|
83
|
+
chunk = "g g o".split " "
|
84
|
+
api.replace_in_part( original, chunk, 2, 2).join.should eq "faggot"
|
85
|
+
original.join.should eq "fabt"
|
86
|
+
chunk.join.should eq "ggo"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should replace as much as possible and then just append the rest in the case the replacement is longer than the original" do
|
91
|
+
original = "asd".split ""
|
92
|
+
chunk = "sshole".split ""
|
93
|
+
api.replace_in_part(original, chunk, 1).join.should eq "asshole"
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should return the chunk if the original array is empty; it should ignore the other options" do
|
97
|
+
api.replace_in_part([], [1,2,3,4], 42).should eq [1,2,3,4]
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should return a cropped version of the array if the replacement chunk is empty" do
|
101
|
+
api.replace_in_part([1,2,3,4], [], 2).should eq [1,2]
|
102
|
+
api.replace_in_part([0,1,2,3,4,5,6,7],[], 2, 4).should eq [0,1,5,6,7]
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
class CascadeTest
|
4
|
+
include Cascadence::Stateful
|
5
|
+
|
6
|
+
cascading_order :step1, :step2, :step3
|
7
|
+
|
8
|
+
attr_reader :foo
|
9
|
+
|
10
|
+
def step1
|
11
|
+
@foo = 2
|
12
|
+
end
|
13
|
+
|
14
|
+
def step2
|
15
|
+
@foo *= 3
|
16
|
+
end
|
17
|
+
|
18
|
+
def step3
|
19
|
+
@foo -= 5
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe Cascadence do
|
24
|
+
|
25
|
+
before :each do
|
26
|
+
@test = CascadeTest.new
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "CascadeTest.new" do
|
30
|
+
|
31
|
+
it "should have the cascadence_position property" do
|
32
|
+
@test.should respond_to :cascadence_position
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should have a null current step" do
|
36
|
+
@test.current_step_name.should be_nil
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should have step1 as it's next step" do
|
40
|
+
@test.next_step_name.should eq :step1
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "CascadeTest" do
|
46
|
+
|
47
|
+
it "should have the cascadence_order property" do
|
48
|
+
CascadeTest.should respond_to :cascadence_order
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "run next" do
|
54
|
+
|
55
|
+
it "should run the first thing specified by the cascadence order" do
|
56
|
+
@test.run_next.foo.should eq 2
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should run the first two steps specified by the cascadence order" do
|
60
|
+
@test.run_next.tap do |cascade|
|
61
|
+
cascade.foo.should eq 2
|
62
|
+
end.run_next.foo.should eq 6
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should run all 3 steps specified by the cascadence order" do
|
66
|
+
@test.run_next.run_next.run_next.foo.should eq 1
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should not do anything to the result on extra calls" do
|
70
|
+
exp = [2,6,1]
|
71
|
+
(0..6).to_a.inject(@test) do |mem, nex|
|
72
|
+
n = nex < 3 ? nex : 2
|
73
|
+
res = mem.run_next
|
74
|
+
res.class.should eq CascadeTest
|
75
|
+
res.foo.should_not be_nil
|
76
|
+
exp[n].should_not be_nil
|
77
|
+
res.foo.should eq exp[n]
|
78
|
+
res
|
79
|
+
end.foo.should eq exp.last
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "run states" do
|
84
|
+
|
85
|
+
let(:final) { @test.run_states }
|
86
|
+
|
87
|
+
it "should have a valid final state" do
|
88
|
+
final.should_not be_nil
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should have maintained the correct cascadence order" do
|
92
|
+
final.class.cascadence_order.should eq [:step1, :step2, :step3]
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should have advanced to the final cascadence position" do
|
96
|
+
final.cascadence_position.should eq 2
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should have the correct cascadence result" do
|
100
|
+
final.foo.should eq 1
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "run until" do
|
106
|
+
|
107
|
+
it "should run to a specified block" do
|
108
|
+
result = @test.run_until do |state|
|
109
|
+
:step3 == state.current_step_name
|
110
|
+
end
|
111
|
+
result.current_step_name.should eq :step3
|
112
|
+
result.foo.should eq 1
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should run to a specified order" do
|
116
|
+
@test.run_until(:step2).foo.should eq 6
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should run to a specified number" do
|
120
|
+
@test.run_until(1).foo.should eq 6
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should run to a specified foreign class" do
|
124
|
+
checker = lambda do |state|
|
125
|
+
state.current_step_name == :step3
|
126
|
+
end
|
127
|
+
@test.run_until(checker).foo.should eq 1
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should have the same result when calling successively" do
|
131
|
+
@test.run_until.run_until.run_until.foo.should eq 1
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Cascadence do
|
4
|
+
it "should pass the presence sanity test" do
|
5
|
+
Cascadence.class.should eq Module
|
6
|
+
end
|
7
|
+
|
8
|
+
[:Flow, :ClassMethods, :Stateful, :Helper].each do |constant|
|
9
|
+
it "should contain the correct #{constant} constant" do
|
10
|
+
Cascadence.const_get(constant).should_not be_nil
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/spec/spec_helper.rb
ADDED