cascadence 0.1.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.
- 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