davidlee-state-fu 0.3.1 → 0.10.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.
Files changed (90) hide show
  1. data/README.textile +124 -34
  2. data/Rakefile +36 -30
  3. data/lib/no_stdout.rb +1 -1
  4. data/lib/state-fu.rb +9 -8
  5. data/lib/state_fu/active_support_lite/array/access.rb +12 -5
  6. data/lib/state_fu/active_support_lite/array/conversions.rb +10 -4
  7. data/lib/state_fu/active_support_lite/array/extract_options.rb +5 -4
  8. data/lib/state_fu/active_support_lite/array/grouping.rb +7 -4
  9. data/lib/state_fu/active_support_lite/array/random_access.rb +4 -3
  10. data/lib/state_fu/active_support_lite/array/wrapper.rb +4 -3
  11. data/lib/state_fu/active_support_lite/array.rb +3 -1
  12. data/lib/state_fu/active_support_lite/blank.rb +18 -9
  13. data/lib/state_fu/active_support_lite/cattr_reader.rb +4 -1
  14. data/lib/state_fu/active_support_lite/keys.rb +8 -3
  15. data/lib/state_fu/active_support_lite/misc.rb +6 -4
  16. data/lib/state_fu/active_support_lite/module/delegation.rb +130 -0
  17. data/lib/state_fu/active_support_lite/module.rb +1 -0
  18. data/lib/state_fu/active_support_lite/object.rb +5 -2
  19. data/lib/state_fu/active_support_lite/string.rb +6 -1
  20. data/lib/state_fu/active_support_lite/symbol.rb +2 -1
  21. data/lib/state_fu/applicable.rb +41 -0
  22. data/lib/state_fu/{helper.rb → arrays.rb} +45 -121
  23. data/lib/state_fu/binding.rb +136 -159
  24. data/lib/state_fu/core_ext.rb +78 -10
  25. data/lib/state_fu/event.rb +112 -48
  26. data/lib/state_fu/exceptions.rb +80 -34
  27. data/lib/state_fu/executioner.rb +149 -0
  28. data/lib/state_fu/has_options.rb +16 -0
  29. data/lib/state_fu/hooks.rb +21 -16
  30. data/lib/state_fu/interface.rb +80 -83
  31. data/lib/state_fu/lathe.rb +361 -148
  32. data/lib/state_fu/logger.rb +122 -45
  33. data/lib/state_fu/machine.rb +60 -32
  34. data/lib/state_fu/method_factory.rb +180 -72
  35. data/lib/state_fu/methodical.rb +17 -0
  36. data/lib/state_fu/persistence/active_record.rb +6 -1
  37. data/lib/state_fu/persistence/attribute.rb +1 -0
  38. data/lib/state_fu/persistence/base.rb +8 -6
  39. data/lib/state_fu/persistence.rb +94 -23
  40. data/lib/state_fu/sprocket.rb +26 -11
  41. data/lib/state_fu/state.rb +8 -27
  42. data/lib/state_fu/transition.rb +207 -98
  43. data/lib/state_fu/transition_query.rb +214 -0
  44. data/lib/state_fu.rb +1 -0
  45. data/lib/tasks/spec_last.rake +46 -0
  46. data/lib/tasks/state_fu.rake +57 -0
  47. data/lib/vizier.rb +61 -61
  48. data/spec/custom_formatter.rb +49 -0
  49. data/spec/features/binding_and_transition_helper_mixin_spec.rb +2 -2
  50. data/spec/features/method_missing_only_once_spec.rb +28 -0
  51. data/spec/features/not_requirements_spec.rb +83 -46
  52. data/spec/features/plotter_spec.rb +97 -0
  53. data/spec/features/shared_log_spec.rb +7 -0
  54. data/spec/features/singleton_machine_spec.rb +39 -0
  55. data/spec/features/state_and_array_options_accessor_spec.rb +1 -1
  56. data/spec/features/{transition_boolean_comparison.rb → transition_boolean_comparison_spec.rb} +29 -18
  57. data/spec/helper.rb +6 -117
  58. data/spec/integration/active_record_persistence_spec.rb +18 -4
  59. data/spec/integration/binding_extension_spec.rb +1 -1
  60. data/spec/integration/class_accessor_spec.rb +49 -59
  61. data/spec/integration/event_definition_spec.rb +20 -20
  62. data/spec/integration/example_01_document_spec.rb +13 -8
  63. data/spec/integration/example_02_string_spec.rb +3 -2
  64. data/spec/integration/instance_accessor_spec.rb +16 -19
  65. data/spec/integration/lathe_extension_spec.rb +2 -2
  66. data/spec/integration/machine_duplication_spec.rb +59 -37
  67. data/spec/integration/relaxdb_persistence_spec.rb +6 -3
  68. data/spec/integration/requirement_reflection_spec.rb +66 -57
  69. data/spec/integration/state_definition_spec.rb +72 -66
  70. data/spec/integration/transition_spec.rb +169 -173
  71. data/spec/spec.opts +5 -3
  72. data/spec/spec_helper.rb +132 -0
  73. data/spec/state_fu_spec.rb +870 -0
  74. data/spec/units/binding_spec.rb +33 -22
  75. data/spec/units/event_spec.rb +3 -22
  76. data/spec/units/exceptions_spec.rb +7 -0
  77. data/spec/units/lathe_spec.rb +7 -7
  78. data/spec/units/machine_spec.rb +67 -75
  79. data/spec/units/method_factory_spec.rb +55 -48
  80. data/spec/units/sprocket_spec.rb +5 -7
  81. data/spec/units/state_spec.rb +33 -24
  82. metadata +31 -19
  83. data/lib/state_fu/active_support_lite/inheritable_attributes.rb +0 -1
  84. data/lib/state_fu/fu_space.rb +0 -51
  85. data/lib/state_fu/mock_transition.rb +0 -38
  86. data/spec/BDD/plotter_spec.rb +0 -115
  87. data/spec/integration/dynamic_requirement_spec.rb +0 -160
  88. data/spec/integration/ex_machine_for_accounts_spec.rb +0 -79
  89. data/spec/integration/sanity_spec.rb +0 -31
  90. data/spec/units/fu_space_spec.rb +0 -95
@@ -0,0 +1,214 @@
1
+ module StateFu
2
+ class TransitionQuery #< Array
3
+ attr_accessor :binding, :options, :result, :args, :block
4
+
5
+ def initialize(binding, options={})
6
+ defaults = { :valid => true, :cyclic => nil }
7
+ @options = defaults.merge(options).symbolize_keys
8
+ @binding = binding
9
+ end
10
+
11
+ include Enumerable
12
+
13
+ def each *a, &b
14
+ result.each *a, &b
15
+ end
16
+
17
+ def method_missing(method_name, *args, &block)
18
+ if result.respond_to?(method_name, true)
19
+ result.__send__(method_name, *args, &block)
20
+ else
21
+ super(method_name, *args, &block)
22
+ end
23
+ end
24
+
25
+ #
26
+ #
27
+ #
28
+
29
+ def find( event_or_array )
30
+ event, target = parse_destination(event_or_array)
31
+ _args, _block = @args, @block
32
+ returning binding.new_transition(event, target) do |t|
33
+ t.apply!(&_block) if _block
34
+ if _args
35
+ t.args = _args
36
+ end
37
+ end
38
+ end
39
+
40
+ def cyclic
41
+ @options.merge! :cyclic => true
42
+ self
43
+ end
44
+
45
+ def not_cyclic
46
+ @options.merge! :cyclic => false
47
+ self
48
+ end
49
+
50
+ def valid
51
+ @options.merge! :valid => true
52
+ self
53
+ end
54
+
55
+ def not_valid
56
+ @options.merge! :valid => false
57
+ self
58
+ end
59
+ alias_method :invalid, :not_valid
60
+
61
+ def to state
62
+ @options.merge! :target => state
63
+ self
64
+ end
65
+
66
+ def for event
67
+ @options.merge! :event => event
68
+ self
69
+ end
70
+
71
+ def simple
72
+ @options.merge! :simple => true
73
+ self
74
+ end
75
+
76
+ #
77
+ #
78
+ #
79
+
80
+ def singular
81
+ result.first if result.length == 1
82
+ end
83
+
84
+ def next
85
+ @options[:cyclic] ||= false
86
+ singular
87
+ end
88
+
89
+ def next_state
90
+ @options[:cyclic] ||= false
91
+ if result.map(&:target).uniq.length == 1
92
+ result.first.target
93
+ end
94
+ end
95
+
96
+ def next_event
97
+ @options[:cyclic] ||= false
98
+ if result.map(&:event).uniq.length == 1
99
+ result.first.event
100
+ end
101
+ end
102
+
103
+ #
104
+ #
105
+ #
106
+
107
+ def events
108
+ map {|t| t.event }
109
+ end
110
+
111
+ def targets
112
+ map {|t| t.target }
113
+ end
114
+
115
+ def apply! # (&block
116
+ result.each { |t| t.apply &block if block }
117
+ end
118
+
119
+ def with(*args, &block)
120
+ @args = args
121
+ @block = block
122
+ self
123
+ end
124
+
125
+ def all_destinations
126
+ binding.events.inject([]){ |arr, evt| arr += evt.targets.map{|tgt| [evt,tgt] }; arr}.uniq
127
+ end
128
+
129
+ def all_destination_names
130
+ all_destinations.map {|tuple| tuple.map(&:to_sym) }
131
+ end
132
+
133
+ private
134
+
135
+ #
136
+ # Result
137
+ #
138
+
139
+ module Result
140
+ def states
141
+ map(&:target).uniq.extend StateArray
142
+ end
143
+ alias_method :targets, :states
144
+ alias_method :next_states, :states
145
+
146
+ def events
147
+ map(&:event).uniq.extend EventArray
148
+ end
149
+ end # Result
150
+
151
+ def result
152
+ @result = binding.events.select do |e|
153
+ case options[:cyclic]
154
+ when true
155
+ e.cycle?
156
+ when false
157
+ !e.cycle?
158
+ else
159
+ true
160
+ end
161
+ end.map do |event|
162
+ next if options[:event] and event != options[:event]
163
+ returning [] do |ts|
164
+
165
+ # TODO hmm ... "sequences" ... delete this?
166
+ if options[:sequences]
167
+ if target = event.target_for_origin(current_state)
168
+ ts << binding.transition([event,target], *args) unless options[:cyclic]
169
+ end
170
+ end
171
+
172
+ if event.targets
173
+ next unless event.target if options[:simple]
174
+ event.targets.flatten.each do |target|
175
+ next if options[:target] and target != options[:target]
176
+ t = binding.new_transition( event, target, *args)
177
+ ts << t if (t.valid? or !options[:valid])
178
+ end
179
+ end
180
+
181
+ end
182
+ end.flatten.extend(Result)
183
+
184
+ if @args || @block
185
+ @result.each do |t|
186
+ t.apply!( &@block) if @block
187
+ t.args = @args if @args
188
+ end
189
+ end
190
+
191
+ @result
192
+ end # result
193
+
194
+ # sanitizes / extracts destination for find.
195
+ #
196
+ # takes a single, simple (one target only) event,
197
+ # or an array of [event, target],
198
+ # or one of the above with symbols in place of the objects themselves.
199
+ def parse_destination(event_or_array)
200
+ case event_or_array
201
+ when Event, Symbol
202
+ event = event_or_array
203
+ target = nil
204
+ when Array
205
+ event, target = *event_or_array
206
+ end
207
+ raise ArgumentError.new( [event,target].inspect ) unless
208
+ [Event, Symbol].include?(event.class) &&
209
+ [State, Symbol, NilClass].include?(target.class)
210
+ [event, target]
211
+ end # parse_destination
212
+
213
+ end
214
+ end
data/lib/state_fu.rb ADDED
@@ -0,0 +1 @@
1
+ require File.expand_path(File.join(File.basename(__FILE__, 'state-fu')))
@@ -0,0 +1,46 @@
1
+ require 'fileutils'
2
+
3
+ unless Object.const_defined?('STATE_FU_APP_PATH')
4
+ STATE_FU_APP_PATH = Object.const_defined?('RAILS_ROOT') ? RAILS_ROOT : File.join( File.dirname(__FILE__), '/../..')
5
+ end
6
+
7
+ unless Object.const_defined?('STATE_FU_PLUGIN_PATH')
8
+ STATE_FU_PLUGIN_PATH = Object.const_defined?('RAILS_ROOT') ? File.join( RAILS_ROOT, '/vendor/plugins/state-fu' ) : STATE_FU_APP_PATH
9
+ end
10
+
11
+ namespace :spec do
12
+ def find_last_modified_spec
13
+ require 'find'
14
+ specs = []
15
+ Find.find( File.expand_path(File.join(STATE_FU_APP_PATH,'spec'))) do |f|
16
+ next unless f !~ /\.#/ && f =~ /_spec.rb$/
17
+ specs << f
18
+ end
19
+ spec = specs.sort_by { |spec| File.stat( spec ).mtime }.last
20
+ end
21
+
22
+ desc "runs the last modified spec; L=n runs only that line"
23
+ Spec::Rake::SpecTask.new(:last) do |t|
24
+ specfile = find_last_modified_spec || return
25
+ t.verbose = true
26
+ t.spec_opts = ["-c","-b","-u"]
27
+ if ENV['L']
28
+ t.spec_opts += ["-l", ENV["L"],"-f", "specdoc"]
29
+ else
30
+ t.spec_opts += ["-f", "profile"]
31
+ end
32
+ t.spec_files = FileList[specfile]
33
+ end
34
+
35
+ desc "runs all specs, or those which last failed"
36
+ Spec::Rake::SpecTask.new(:faily) do |t|
37
+ specfile = find_last_modified_spec || return
38
+ faily = 'spec.fail'
39
+ t.verbose = true
40
+ t.spec_opts = ["-f","failing_examples:#{faily}", "-f","n","-c","-b","-u"]
41
+ if File.exists?(faily) && File.read(faily).split("\n")[0] != ""
42
+ t.spec_opts << ["-e",faily]
43
+ end
44
+ end
45
+
46
+ end
@@ -0,0 +1,57 @@
1
+ require 'fileutils'
2
+
3
+ unless Object.const_defined?('STATE_FU_APP_PATH')
4
+ STATE_FU_APP_PATH = Object.const_defined?('RAILS_ROOT') ? RAILS_ROOT : File.join( File.dirname(__FILE__), '/../..')
5
+ end
6
+
7
+ unless Object.const_defined?('STATE_FU_PLUGIN_PATH')
8
+ STATE_FU_PLUGIN_PATH = Object.const_defined?('RAILS_ROOT') ? File.join( RAILS_ROOT, '/vendor/plugins/state-fu' ) : STATE_FU_APP_PATH
9
+ end
10
+
11
+ namespace :state_fu do
12
+
13
+ task :update do
14
+ path = STATE_FU_PLUGIN_PATH
15
+ pwd = FileUtils.pwd
16
+ FileUtils.cd( path )
17
+ system('git pull')
18
+ FileUtils.cd pwd
19
+ end
20
+
21
+ def graph_name( klass, machine, doc_path = false )
22
+ parts = ["#{klass}_#{machine}"]
23
+ if doc_path
24
+ folder = parts.unshift( File.join( STATE_FU_APP_PATH, "doc/") )
25
+ FileUtils.mkdir_p( folder )
26
+ parts.push( '.png' )
27
+ end
28
+ parts.join
29
+ end
30
+
31
+ def graph( klass, machine )
32
+ name = graph_name( klass, machine )
33
+ graphviz = `which dot`.strip || raise("Graphviz not installed? Can't find dot executable!")
34
+ puts graphviz
35
+ tmp_dot = "/tmp/#{name}.dot"
36
+ klass.machine( machine.to_sym ).graphviz.save_as( tmp_dot )
37
+ tmp_png = tmp_dot + '.png'
38
+ doc_png = graph_name( klass, machine, true )
39
+ puts( "#{graphviz} -Tpng -O #{tmp_dot}" )
40
+ system( "#{graphviz} -Tpng -O #{tmp_dot}" )
41
+ FileUtils.cp tmp_png, doc_png
42
+ doc_png
43
+ end
44
+
45
+ desc "Graph workflows with dot"
46
+ task :graph => :environment do |t|
47
+ state_fu_classes = ObjectSpace.each_object { |o| x << o if o.respond_to? :machines }
48
+ state_fu_classes.each do |klass|
49
+ klass.state_fu_machines.each do |machine_name, machine|
50
+ STDERR.puts "#{klass} -> #{machine_name.inspect}"
51
+ doc_png = graph( klass, machine_name )
52
+ # yield doc_png if block_given?
53
+ end
54
+ end
55
+ # `open #{doc_png}`
56
+ end
57
+ end
data/lib/vizier.rb CHANGED
@@ -4,43 +4,43 @@ begin
4
4
  require File.join(File.dirname(__FILE__), '/state_fu/core_ext' )
5
5
  rescue LoadError
6
6
  require 'activesupport'
7
- end
8
-
9
- # sorry, there's only Heisendocumentation (if I realize anyone's looking for
10
- # them, I might write some)
11
-
12
- # temporary dirty hack
13
-
14
- module Vizier
15
-
7
+ end
8
+
9
+ # Vizier is a simple library to help generate dot output for graphviz. It is used by StateFu's rake
10
+ # tasks to generate graphs of state machines.
11
+ #
12
+ # Sorry, there's only Heisendocumentation (if I realize anyone's looking for docs, I might write some)
13
+ #
14
+ module Vizier #:nodoc:all
15
+
16
16
  module Support
17
17
  LEGAL_CHARS = 'a-zA-Z0-9_'
18
-
18
+
19
19
  def attributes=( attrs )
20
20
  @attributes = attrs.symbolize_keys!.extend( Attributes )
21
21
  end
22
-
22
+
23
23
  def attributes
24
24
  (@attributes ||= {}).extend( Attributes )
25
25
  end
26
-
26
+
27
27
  def legal?( str )
28
28
  str =~ /^[#{LEGAL_CHARS}]+$/ && str == str.split
29
29
  end
30
-
30
+
31
31
  def sanitize(str)
32
32
  sanitize( str )
33
33
  end
34
-
34
+
35
35
  def quote( str )
36
36
  return str if legal?( str )
37
37
  '"' + str.to_s.gsub(/"/,'\"') + '"'
38
38
  end
39
-
39
+
40
40
  def self.included( klass )
41
41
  klass.extend( ClassMethods )
42
42
  end
43
-
43
+
44
44
  module Finder
45
45
  def []( idx )
46
46
  begin
@@ -56,12 +56,12 @@ module Vizier
56
56
  end
57
57
  end
58
58
  end
59
-
59
+
60
60
  module ClassMethods
61
61
  def sanitize( str )
62
62
  str.to_s.gsub(/[^#{LEGAL_CHARS}]/,'_').gsub(/__+/,'_')
63
63
  end
64
-
64
+
65
65
  def finder( name )
66
66
  class_eval do
67
67
  define_method name do
@@ -71,63 +71,63 @@ module Vizier
71
71
  end
72
72
  end
73
73
  end
74
-
74
+
75
75
  module Attributes
76
76
  include Support
77
-
77
+
78
78
  def to_s
79
79
  return '[]' if empty?
80
80
  '[ ' + self.map do |k,v|
81
81
  "#{quote k} = #{quote v}"
82
82
  end.join(" ") + ' ]'
83
83
  end
84
-
84
+
85
85
  end
86
-
86
+
87
87
  class Base
88
88
  def [](k)
89
89
  attributes[k.to_sym]
90
90
  end
91
-
91
+
92
92
  def []=(k,v)
93
93
  attributes[k.to_sym] = v
94
94
  end
95
95
  end
96
-
96
+
97
97
  class Link < Base
98
98
  include Support
99
99
  attr_accessor :from
100
100
  attr_accessor :to
101
-
101
+
102
102
  def initialize( from, to, attrs={} )
103
103
  self.attributes = attrs
104
104
  @from = extract_name( from )
105
105
  @to = extract_name( to )
106
106
  end
107
-
107
+
108
108
  def extract_name( o )
109
109
  o.is_a?(String) ? o : o.name
110
110
  end
111
-
111
+
112
112
  def to_str
113
113
  "#{quote from} -> #{quote to} #{attributes};"
114
114
  end
115
115
  end
116
-
116
+
117
117
  # TODO ..
118
118
  module Label
119
119
  def []( i )
120
-
120
+
121
121
  end
122
122
  end
123
-
123
+
124
124
  class Node < Base
125
125
  include Support
126
-
126
+
127
127
  attr_accessor :object
128
128
  attr_accessor :fields
129
129
  attr_accessor :name
130
-
130
+
131
131
  def initialize( name = nil, attrs={} )
132
132
  self.attributes = attrs
133
133
  if name.is_a?( String )
@@ -139,65 +139,65 @@ module Vizier
139
139
  @label = attrs.delete(:label) || Node.first_response( @object, :name, :identifier, :label ) || name
140
140
  end
141
141
  end
142
-
142
+
143
143
  def self.make_name( obj )
144
144
  sanitize [ obj.class, first_response( obj, :name, :identifier, :id, :hash)].join('_')
145
145
  end
146
-
146
+
147
147
  def self.first_response obj, *method_names
148
148
  responder = method_names.flatten.detect { |m| obj.respond_to?(m) }
149
149
  obj.send( responder ) unless responder.nil?
150
150
  end
151
-
151
+
152
152
  def name=( str )
153
153
  @name = str.to_s.gsub(/[^a-zA-Z0-9_]/,'_').gsub(/__+/,'_')
154
154
  end
155
-
155
+
156
156
  def to_str
157
157
  "#{quote name} #{attributes.to_s};"
158
158
  end
159
-
159
+
160
160
  def to_s
161
161
  quote( name )
162
162
  end
163
163
  end
164
-
164
+
165
165
  class SubGraph < Base
166
166
  include Support
167
-
167
+
168
168
  finder :nodes
169
-
169
+
170
170
  attr_accessor :links
171
171
  attr_accessor :name
172
-
172
+
173
173
  def initialize( name, attrs={} )
174
174
  self.attributes = attrs
175
175
  @node = {}
176
176
  @edge = {}
177
-
177
+
178
178
  @name = name
179
179
  @nodes = []
180
180
  @links = []
181
181
  end
182
-
182
+
183
183
  def node(attrs={})
184
184
  (@node ||= {}).merge!(attrs).extend(Attributes)
185
185
  end
186
-
186
+
187
187
  def graph(attrs={})
188
188
  self.attributes.merge!(attrs).extend(Attributes)
189
189
  end
190
-
190
+
191
191
  def edge(attrs={})
192
192
  (@edge ||= {}).merge!(attrs).extend(Attributes)
193
193
  end
194
-
194
+
195
195
  def add_node( n, a={} )
196
196
  returning Node.new(n,a) do |n|
197
197
  @nodes << n
198
198
  end
199
199
  end
200
-
200
+
201
201
  def add_link(from, to, a={})
202
202
  returning Link.new( from, to, a) do |l|
203
203
  @links << l
@@ -205,7 +205,7 @@ module Vizier
205
205
  end
206
206
  alias_method :connect, :add_link
207
207
  alias_method :add_edge, :add_link
208
-
208
+
209
209
  def build(lines = [], indent = 0)
210
210
  lines.map do |line|
211
211
  if line.is_a?( Array )
@@ -215,17 +215,17 @@ module Vizier
215
215
  end
216
216
  end.join("\n")
217
217
  end
218
-
218
+
219
219
  def write_comment( str, j = 0 )
220
220
  l = 40 - (j * 4)
221
221
  i = ' ' * (j * 4)
222
222
  "\n#{i}/*#{'*'*(l-2)}\n#{i}** #{ str.ljust((l - (6) - (j*4)),' ') }#{i} **\n#{i}#{'*'*(l-1)}/"
223
223
  end
224
-
224
+
225
225
  def comment(str)
226
226
  write_comment(str, 2)
227
227
  end
228
-
228
+
229
229
  def to_str
230
230
  build( ["subgraph #{quote name} {",
231
231
  [ # attributes.map {|k,v| "#{quote k} = #{quote v};" },
@@ -240,16 +240,16 @@ module Vizier
240
240
  ])
241
241
  end
242
242
  alias_method :generate!, :to_str
243
-
243
+
244
244
  end
245
-
245
+
246
246
  class Graph < SubGraph
247
247
  finder :subgraphs
248
-
248
+
249
249
  def comment( str )
250
250
  write_comment( str, 1 )
251
251
  end
252
-
252
+
253
253
  def to_str
254
254
  build(["digraph #{quote name} {",
255
255
  [
@@ -267,18 +267,18 @@ module Vizier
267
267
  "}"])
268
268
  end
269
269
  alias_method :generate!, :to_str
270
-
270
+
271
271
  def publish!( a = {} )
272
272
  generate! # -> png
273
273
  end
274
-
274
+
275
275
  def subgraph(name, a = {})
276
276
  returning( SubGraph.new(name, a)) do |g|
277
277
  @subgraphs << g
278
278
  yield g if block_given?
279
279
  end
280
280
  end
281
-
281
+
282
282
  def cluster(name = nil, a = {}, &block)
283
283
  if name && name = "cluster_#{name}"
284
284
  subgraph( name, a, &block )
@@ -286,15 +286,15 @@ module Vizier
286
286
  clusters
287
287
  end
288
288
  end
289
-
289
+
290
290
  def clusters
291
291
  @subgraphs.select {|s| s.name =~ /^cluster_/ }.extend( Finder )
292
292
  end
293
-
293
+
294
294
  def initialize(name = 'my_graph', attrs = {})
295
295
  @subgraphs = []
296
296
  super( name, attrs )
297
297
  yield self if block_given?
298
298
  end
299
299
  end
300
- end
300
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec/runner/formatter/progress_bar_formatter'
2
+ class CustomFormatter < Spec::Runner::Formatter::ProgressBarFormatter
3
+ def add_line(l)
4
+ (@lines||=[]) << l
5
+ end
6
+
7
+ def dump_pending
8
+ unless @pending_examples.empty?
9
+ lpad = @pending_examples.map{|e|e[2].length}.max
10
+ @output.puts
11
+ @output.puts "Pending: #{@pending_examples.length}"
12
+ @pending_examples.each do |pending_example|
13
+ @output.puts yellow("#{pending_example[2].strip.ljust(lpad)} # - #{pending_example[1]}")
14
+ end
15
+ end
16
+ @output.flush
17
+ end
18
+
19
+ # def example_failed(example, counter, failure)
20
+ # failure.instance_eval do
21
+ # (class<<self;self;end).class_eval { attr_accessor :location }
22
+ # end
23
+ # failure.location = example.location
24
+ # super(example,counter,failure)
25
+ # end
26
+
27
+ def dump_summary(duration, example_count, failure_count, pending_count)
28
+ if @lines
29
+ @output.puts "="*72
30
+ @lines.each do |line|
31
+ @output.puts line
32
+ end
33
+ @output.puts "="*72
34
+ end
35
+ super(duration, example_count, failure_count, pending_count)
36
+ end
37
+
38
+ def dump_failure(counter, failure)
39
+ @output.puts
40
+ @output.puts "#{counter.to_s})"
41
+ # @output.puts failure.location
42
+ @output.puts colorize_failure("#{failure.header}\n#{failure.exception.message}", failure.inspect)
43
+ @output.puts format_backtrace(failure.exception.backtrace)
44
+ #failure.exception
45
+ line = failure.exception.backtrace.last rescue failure.exception.inspect
46
+ add_line line
47
+ @output.flush
48
+ end
49
+ end
@@ -37,7 +37,7 @@ describe "extending bindings and transitions with Lathe#helper" do
37
37
  attr_accessor :ok
38
38
  end
39
39
 
40
- @machine = Klass.machine do
40
+ @machine = Klass.state_fu_machine do
41
41
  helper MySpecHelper::BindingExampleHelper
42
42
  helper 'my_spec_helper/other_example_helper'
43
43
 
@@ -50,7 +50,7 @@ describe "extending bindings and transitions with Lathe#helper" do
50
50
  end
51
51
  end
52
52
 
53
- @other_machine = Klass.machine(:other) do
53
+ @other_machine = Klass.state_fu_machine(:other) do
54
54
  helper ::MySpecHelper::OtherExampleHelper
55
55
  end
56
56
  @obj = Klass.new