ellington 0.0.5 → 0.0.6

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.
@@ -43,6 +43,10 @@ module Ellington
43
43
  @state_history ||= []
44
44
  end
45
45
 
46
+ def state_history_includes?(*states)
47
+ (state_history & states).length == states.length
48
+ end
49
+
46
50
  def transition_to(new_state)
47
51
  if !locked?
48
52
  message = "Cannot transition an unlocked #{self.class.name}'s state"
@@ -40,10 +40,11 @@ module Ellington
40
40
  (@subclasses ||= []) << subclass
41
41
  end
42
42
 
43
- def generate_graphs(dir)
43
+ def generate_graphs(dir, options={})
44
+ options[:format] ||= :svg
44
45
  FileUtils.mkdir_p(dir)
45
46
  @subclasses.each do |subclass|
46
- Ellington::Visualizer.new(subclass.new, dir).graph
47
+ Ellington::Visualizer.new(subclass.new, dir, options[:format]).graph_all
47
48
  end
48
49
  end
49
50
 
@@ -122,6 +123,7 @@ module Ellington
122
123
  log route_info
123
124
  end
124
125
  Ellington.logger.info "\n" if Ellington.logger
126
+ binding.pry
125
127
  end
126
128
 
127
129
  required_connections.each do |connection|
@@ -1,3 +1,3 @@
1
1
  module Ellington
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  end
@@ -28,76 +28,122 @@ module Ellington
28
28
  end
29
29
  end
30
30
 
31
- attr_reader :route, :dir
31
+ attr_reader :route, :dir, :format
32
32
 
33
- def initialize(route, dir)
33
+ def initialize(route, dir, format=:svg)
34
34
  @route = route
35
35
  @dir = dir
36
+ @format = format
36
37
  end
37
38
 
38
- def graph
39
- graph_route_basic
40
- graph_route
41
- graph_lines_basic
42
- graph_lines
39
+ FONTNAME = "Helvetica"
40
+ RANKSEP = 0.4
41
+ NODE_COLOR = "white"
42
+ NODE_COLOR_VIRTUAL = "gray50"
43
+ NODE_COLOR_LINE_GOAL = "green2"
44
+ NODE_COLOR_ROUTE_GOAL = "gold"
45
+ NODE_COLOR_PASSENGER_HIT = "royalblue1"
46
+ NODE_FILLCOLOR = "white"
47
+ NODE_FILLCOLOR_LINE_GOAL = "green2"
48
+ NODE_FILLCOLOR_ROUTE_GOAL = "gold"
49
+ NODE_FONTCOLOR_VIRTUAL = "gray40"
50
+ NODE_SHAPE = "box"
51
+ NODE_STYLE = "filled,rounded"
52
+ NODE_STYLE_VIRTUAL = "rounded"
53
+ NODE_PENWIDTH_PASSENGER_HIT = 2
54
+ EDGE_PENWIDTH_PASSENGER_HIT = 2
55
+ EDGE_COLOR_PASSENGER_HIT = "royalblue1"
56
+ EDGE_STYLE_PASSENGER_MISS = "dotted"
57
+ CLUSTER_STYLE = "filled"
58
+ CLUSTER_COLOR = "gray70"
59
+ CLUSTER_FILLCOLOR = "gray70"
60
+ CLUSTER_PENCOLOR = "gray50"
61
+
62
+ def graph_all(passenger=nil)
63
+ graph_route_basic passenger
64
+ graph_route passenger
65
+ graph_lines_basic passenger
66
+ graph_lines passenger
43
67
  end
44
68
 
45
- def graph_lines_basic
46
- g = Node.new(nil, GraphViz.new("G"))
69
+ def graph_lines_basic(passenger=nil)
70
+ g = Node.new(nil, GraphViz.new("GraphLinesBasic"))
71
+ set_graph_defaults g.viz
47
72
  g.viz["label"] = "#{route.name} Lines - basic"
48
- g.viz["ranksep"] = 0.4
49
- g.viz["fontname"] = "Helvetica"
50
- g.viz.node["fontname"] = "Helvetica"
51
- g.viz.node["shape"] = "box"
52
- g.viz.node["style"] = "rounded"
53
73
 
54
74
  route.lines.each_with_index do |line, index|
55
75
  line_cluster = Node.new(line, g.viz.add_graph("cluster#{index}"))
76
+ set_cluster_defaults line_cluster.viz
56
77
  line_cluster.viz["label"] = line.class.name
57
- line_cluster.viz["style"] = "filled"
58
78
  g << line_cluster
59
79
 
60
80
  line.stations.each do |station|
61
81
  station_node = Node.new(station, line_cluster.viz.add_nodes(station.class.name))
62
- station_node.viz["style"] = "filled,rounded"
63
- station_node.viz["color"] = "white"
64
82
  line_cluster << station_node
83
+
84
+ if !(line.goal & station.states.keys).empty?
85
+ station_node.viz["color"] = NODE_COLOR_LINE_GOAL
86
+ station_node.viz["fillcolor"] = NODE_COLOR_LINE_GOAL
87
+ end
88
+
89
+ if !(route.goal & station.states.keys).empty?
90
+ station_node.viz["color"] = NODE_COLOR_ROUTE_GOAL
91
+ station_node.viz["fillcolor"] = NODE_COLOR_ROUTE_GOAL
92
+ end
93
+
94
+ if passenger && !(passenger.state_history & station.states.keys).empty?
95
+ station_node.viz["color"] = NODE_COLOR_PASSENGER_HIT
96
+ station_node.viz["penwidth"] = NODE_PENWIDTH_PASSENGER_HIT
97
+ end
65
98
  end
66
99
 
67
100
  line_cluster.each_with_index.each do |node, node_index|
68
101
  next_node = line_cluster[node_index + 1]
69
- line_cluster.viz.add_edges node.viz, next_node.viz if next_node
102
+ if next_node
103
+ station = node.base
104
+ next_station = next_node.base
105
+ edge = line_cluster.viz.add_edges(node.viz, next_node.viz)
106
+ if passenger
107
+ if color_name(node.viz["color"]) == NODE_COLOR_PASSENGER_HIT &&
108
+ color_name(next_node.viz["color"]) == NODE_COLOR_PASSENGER_HIT
109
+ edge["color"] = EDGE_COLOR_PASSENGER_HIT
110
+ edge["penwidth"] = EDGE_PENWIDTH_PASSENGER_HIT
111
+ else
112
+ edge["style"] = EDGE_STYLE_PASSENGER_MISS
113
+ end
114
+ end
115
+ end
70
116
  end
71
117
  end
72
118
 
73
- file_name = "#{route.name.downcase.gsub("::", "_")}-lines-basic.pdf"
74
- g.viz.output(:pdf => File.join(dir, file_name))
119
+ file_name = "#{route.name.downcase.gsub("::", "_")}-lines-basic.#{format}"
120
+ g.viz.output(format => File.join(dir, file_name))
75
121
  end
76
122
 
77
- def graph_lines
78
- g = Node.new(nil, GraphViz.new("G"))
123
+ def graph_lines(passenger=nil)
124
+ g = Node.new(nil, GraphViz.new("GraphLines"))
125
+ set_graph_defaults g.viz
79
126
  g.viz["label"] = "#{route.name} Lines"
80
- g.viz["ranksep"] = 0.4
81
- g.viz["fontname"] = "Helvetica"
82
- g.viz.node["fontname"] = "Helvetica"
83
- g.viz.node["shape"] = "box"
84
- g.viz.node["style"] = "rounded"
85
127
 
86
128
  route.lines.each_with_index do |line, index|
87
129
  line_cluster = Node.new(line, g.viz.add_graph("cluster#{index}"))
130
+ set_cluster_defaults line_cluster.viz
88
131
  line_cluster.viz["label"] = line.class.name
89
- line_cluster.viz["style"] = "filled"
90
132
  g << line_cluster
91
133
 
92
134
  line.states.keys.each do |state|
93
135
  state_node = Node.new(state, line_cluster.viz.add_nodes(state))
94
- state_node.viz["style"] = "filled,rounded"
95
- state_node.viz["color"] = "white"
96
136
  if line.goal.include?(state)
97
- state_node.viz["color"] = "green2"
137
+ state_node.viz["color"] = NODE_COLOR_LINE_GOAL
138
+ state_node.viz["fillcolor"] = NODE_FILLCOLOR_LINE_GOAL
98
139
  end
99
140
  if route.goal.include?(state)
100
- state_node.viz["color"] = "gold"
141
+ state_node.viz["color"] = NODE_COLOR_ROUTE_GOAL
142
+ state_node.viz["fillcolor"] = NODE_FILLCOLOR_ROUTE_GOAL
143
+ end
144
+ if passenger && passenger.state_history_includes?(state)
145
+ state_node.viz["color"] = NODE_COLOR_PASSENGER_HIT
146
+ state_node.viz["penwidth"] = NODE_PENWIDTH_PASSENGER_HIT
101
147
  end
102
148
  line_cluster << state_node
103
149
  end
@@ -106,45 +152,64 @@ module Ellington
106
152
  a = line_cluster.find(state)
107
153
  (transitions || []).each do |transition|
108
154
  b = line_cluster.find(transition)
109
- line_cluster.viz.add_edges a.viz, b.viz
155
+ edge = line_cluster.viz.add_edges(a.viz, b.viz)
156
+ if passenger
157
+ if passenger.state_history_includes?(state, transition)
158
+ edge["color"] = EDGE_COLOR_PASSENGER_HIT
159
+ edge["penwidth"] = EDGE_PENWIDTH_PASSENGER_HIT
160
+ else
161
+ edge["style"] = EDGE_STYLE_PASSENGER_MISS
162
+ end
163
+ end
110
164
  end
111
165
  end
112
166
  end
113
167
 
114
- file_name = "#{route.name.downcase.gsub("::", "_")}-lines.pdf"
115
- g.viz.output(:pdf => File.join(dir, file_name))
168
+ file_name = "#{route.name.downcase.gsub("::", "_")}-lines.#{format}"
169
+ g.viz.output(format => File.join(dir, file_name))
116
170
  end
117
171
 
118
- def graph_route_basic
119
- g = Node.new(nil, GraphViz.new("G"))
172
+ def graph_route_basic(passenger=nil)
173
+ g = Node.new(nil, GraphViz.new("GraphRouteBasic"))
174
+ set_graph_defaults g.viz
175
+ g.viz["ranksep"] = 1
120
176
  g.viz["label"] = "#{route.name} Route - basic"
121
- g.viz["compound"] = true
122
- g.viz["ranksep"] = 1.2
123
- g.viz["fontname"] = "Helvetica"
124
- g.viz.node["fontname"] = "Helvetica"
125
- g.viz.node["shape"] = "box"
126
- g.viz.node["style"] = "rounded"
127
177
 
128
178
  route.lines.each_with_index do |line, index|
129
179
  line_cluster = Node.new(line, g.viz.add_graph("cluster#{index}"))
180
+ set_cluster_defaults line_cluster.viz
130
181
  line_cluster.viz["label"] = line.class.name
131
- line_cluster.viz["style"] = "filled"
132
182
  g << line_cluster
133
183
 
184
+ passenger_hit = false
134
185
  %w{PASS FAIL ERROR}.each do |state|
135
186
  state_node = Node.new(state, line_cluster.viz.add_nodes("#{line.class.name}#{state}", "label" => state))
136
- state_node.viz["style"] = "filled,rounded"
137
- state_node.viz["color"] = "white"
138
- if !(route.goal & line.stations.map{ |s| "#{state} #{s.name}" }).empty?
139
- state_node.viz["color"] = "gold"
140
- end
141
187
  line_cluster << state_node
188
+ states = line.stations.map{ |s| "#{state} #{s.name}" }
189
+
190
+ if !(line.goal & states).empty?
191
+ state_node.viz["color"] = NODE_COLOR_LINE_GOAL
192
+ state_node.viz["fillcolor"] = NODE_COLOR_LINE_GOAL
193
+ end
194
+
195
+ if !(route.goal & states).empty?
196
+ state_node.viz["color"] = NODE_COLOR_ROUTE_GOAL
197
+ state_node.viz["fillcolor"] = NODE_COLOR_ROUTE_GOAL
198
+ end
199
+
200
+ if passenger
201
+ if !passenger_hit && !(passenger.state_history & line.send("#{state.downcase}ed")).empty?
202
+ passenger_hit = true
203
+ state_node.viz["color"] = NODE_COLOR_PASSENGER_HIT
204
+ state_node.viz["penwidth"] = NODE_PENWIDTH_PASSENGER_HIT
205
+ end
206
+ end
142
207
  end
143
208
  end
144
209
 
145
210
  route.connections.each do |connection|
146
211
  to_node = g.find(connection.line)
147
- from_line = to_node.base
212
+ to_line = to_node.base
148
213
 
149
214
  combos = {}
150
215
  g.to_a.each do |node|
@@ -157,10 +222,10 @@ module Ellington
157
222
  if connection.type == :if_any
158
223
  combos.each do |state, nodes|
159
224
  nodes.each do |node|
160
- to_line = node.base
225
+ from_line = node.base
161
226
  g.viz.add_edges(
162
- node.viz.get_node("#{to_line.class.name}#{state}"),
163
- to_node.viz.get_node("#{from_line.class.name}PASS"),
227
+ node.viz.get_node("#{from_line.class.name}#{state}"),
228
+ to_node.viz.get_node("#{to_line.class.name}PASS"),
164
229
  "lhead" => to_node.viz.id
165
230
  )
166
231
  end
@@ -172,9 +237,9 @@ module Ellington
172
237
  node_name = nodes.map{ |n| n.base.class.name }.join + state
173
238
  node_label = nodes.map{ |n| "#{n.base.class.name} #{state}"}.join("\n")
174
239
  viz = g.viz.add_nodes(node_name, "label" => node_label)
175
- viz["style"] = "rounded"
176
- viz["color"] = "gray50"
177
- viz["fontcolor"] = "gray40"
240
+ viz["style"] = NODE_STYLE_VIRTUAL
241
+ viz["color"] = NODE_COLOR_VIRTUAL
242
+ viz["fontcolor"] = NODE_FONTCOLOR_VIRTUAL
178
243
 
179
244
  nodes.each do |node|
180
245
  from_viz = node.viz.get_node("#{node.base.class.name}#{state}")
@@ -190,41 +255,62 @@ module Ellington
190
255
  end
191
256
  end
192
257
 
193
- file_name = "#{route.name.downcase.gsub("::", "_")}-route-basic.pdf"
194
- g.viz.output(:pdf => File.join(dir, file_name))
258
+ file_name = "#{route.name.downcase.gsub("::", "_")}-route-basic.#{format}"
259
+ g.viz.output(format => File.join(dir, file_name))
195
260
  end
196
261
 
197
- def graph_route
198
- g = Node.new(nil, GraphViz.new("G"))
262
+ def graph_route(passenger=nil)
263
+ g = Node.new(nil, GraphViz.new("GraphRoute"))
264
+ set_graph_defaults g.viz
199
265
  g.viz["label"] = "#{route.name} Lines"
200
- g.viz["compound"] = true
201
266
  g.viz["ranksep"] = 0.8
202
- g.viz["fontname"] = "Helvetica"
203
- g.viz.node["fontname"] = "Helvetica"
204
- g.viz.node["shape"] = "box"
205
- g.viz.node["style"] = "rounded"
206
267
 
207
268
  route.lines.each_with_index do |line, index|
208
269
  line_cluster = Node.new(line, g.viz.add_graph("cluster#{index}"))
270
+ set_cluster_defaults line_cluster.viz
209
271
  line_cluster.viz["label"] = line.class.name
210
- line_cluster.viz["style"] = "filled"
211
272
  g << line_cluster
212
273
 
213
274
  line.states.keys.each do |state|
214
275
  state_node = Node.new(state, line_cluster.viz.add_nodes(state))
215
- state_node.viz["style"] = "filled,rounded"
216
- state_node.viz["color"] = "white"
217
276
  if line.goal.include?(state)
218
- state_node.viz["color"] = "green2"
277
+ state_node.viz["color"] = NODE_COLOR_LINE_GOAL
278
+ state_node.viz["fillcolor"] = NODE_FILLCOLOR_LINE_GOAL
219
279
  end
220
280
  if route.goal.include?(state)
221
- state_node.viz["color"] = "gold"
281
+ state_node.viz["color"] = NODE_COLOR_ROUTE_GOAL
282
+ state_node.viz["fillcolor"] = NODE_FILLCOLOR_ROUTE_GOAL
283
+ end
284
+ if passenger && passenger.state_history_includes?(state)
285
+ state_node.viz["color"] = NODE_COLOR_PASSENGER_HIT
286
+ state_node.viz["penwidth"] = NODE_PENWIDTH_PASSENGER_HIT
222
287
  end
223
288
  line_cluster << state_node
224
289
  end
225
290
  end
226
291
 
227
292
  viz = g.viz.add_nodes(route.initial_state)
293
+ rendered_edges = {}
294
+
295
+ if passenger
296
+ passenger_nodes = g.reduce([]) do |memo, line_cluster|
297
+ line_cluster.children.each do |node|
298
+ if node.viz["color"].to_s.gsub(/\W/, "") == NODE_COLOR_PASSENGER_HIT
299
+ memo << node
300
+ end
301
+ end
302
+ memo
303
+ end
304
+ previous_node = nil
305
+ passenger_nodes.each do |node|
306
+ from_viz = previous_node.nil? ? viz : previous_node.viz
307
+ rendered_edges[from_viz.id + node.viz.id] = true
308
+ edge = g.viz.add_edges(from_viz, node.viz)
309
+ edge["color"] = EDGE_COLOR_PASSENGER_HIT
310
+ edge["penwidth"] = EDGE_PENWIDTH_PASSENGER_HIT
311
+ previous_node = node
312
+ end
313
+ end
228
314
 
229
315
  route.states.each do |from_state, to_states|
230
316
  (to_states || []).each do |to_state|
@@ -237,17 +323,43 @@ module Ellington
237
323
  to_viz = to_node.viz.get_node(to_state) if to_node
238
324
  to_viz ||= g.viz.get_node(to_state)
239
325
 
240
- if from_viz && to_viz
241
- g.viz.add_edges(
326
+ if from_viz && to_viz && !rendered_edges[from_viz.id + to_viz.id]
327
+ rendered_edges[from_viz.id + to_viz.id] = true
328
+ edge = g.viz.add_edges(
242
329
  from_viz,
243
330
  to_viz
244
331
  )
332
+ edge["style"] = EDGE_STYLE_PASSENGER_MISS if passenger
245
333
  end
246
334
  end
247
335
  end
248
336
 
249
- file_name = "#{route.name.downcase.gsub("::", "_")}-route.pdf"
250
- g.viz.output(:pdf => File.join(dir, file_name))
337
+ file_name = "#{route.name.downcase.gsub("::", "_")}-route.#{format}"
338
+ g.viz.output(format => File.join(dir, file_name))
339
+ end
340
+
341
+ private
342
+
343
+ def color_name(graphviz_color)
344
+ graphviz_color.to_s.gsub("\"", "")
345
+ end
346
+
347
+ def set_graph_defaults(graph)
348
+ graph["compound"] = true
349
+ graph["ranksep"] = RANKSEP
350
+ graph["fontname"] = FONTNAME
351
+ graph.node["fontname"] = FONTNAME
352
+ graph.node["shape"] = NODE_SHAPE
353
+ graph.node["style"] = NODE_STYLE
354
+ graph.node["color"] = NODE_COLOR
355
+ graph.node["fillcolor"] = NODE_FILLCOLOR
356
+ end
357
+
358
+ def set_cluster_defaults(cluster)
359
+ cluster["style"] = CLUSTER_STYLE
360
+ cluster["color"] = CLUSTER_COLOR
361
+ cluster["fillcolor"] = CLUSTER_FILLCOLOR
362
+ cluster["pencolor"] = CLUSTER_PENCOLOR
251
363
  end
252
364
 
253
365
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ellington
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-28 00:00:00.000000000 Z
12
+ date: 2013-03-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: hero
@@ -90,7 +90,6 @@ files:
90
90
  - lib/ellington/version.rb
91
91
  - lib/ellington/visualizer.rb
92
92
  - lib/ellington.rb
93
- - Blast.pdf
94
93
  - Gemfile
95
94
  - Gemfile.lock
96
95
  - LICENSE.txt
@@ -134,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
134
133
  version: '0'
135
134
  requirements: []
136
135
  rubyforge_project:
137
- rubygems_version: 1.8.23
136
+ rubygems_version: 1.8.25
138
137
  signing_key:
139
138
  specification_version: 3
140
139
  summary: A micro framework to ensure your projects are easy to manage, develop, &
@@ -157,4 +156,3 @@ test_files:
157
156
  - test/ticket_test.rb
158
157
  - test/transition_info_test.rb
159
158
  - test/unique_type_array_test.rb
160
- has_rdoc:
data/Blast.pdf DELETED
Binary file