laser 0.7.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (319) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +14 -0
  4. data/LICENSE +661 -0
  5. data/README.md +158 -0
  6. data/Rakefile +104 -0
  7. data/VERSION +1 -0
  8. data/bin/laser +7 -0
  9. data/design_docs/goals.md +57 -0
  10. data/design_docs/object_regex.md +426 -0
  11. data/design_docs/type_annotations.md +80 -0
  12. data/ext/laser/BasicBlock.cpp +572 -0
  13. data/ext/laser/BasicBlock.h +118 -0
  14. data/ext/laser/extconf.rb +3 -0
  15. data/features/laser.feature +25 -0
  16. data/features/step_definitions/laser_steps.rb +39 -0
  17. data/features/support/env.rb +14 -0
  18. data/features/support/testdata/1_input +1 -0
  19. data/features/support/testdata/1_output +1 -0
  20. data/features/support/testdata/2_input +4 -0
  21. data/features/support/testdata/2_output +4 -0
  22. data/features/support/testdata/3_input +8 -0
  23. data/features/support/testdata/3_output +11 -0
  24. data/features/support/testdata/4_input +5 -0
  25. data/features/support/testdata/4_output +5 -0
  26. data/features/support/testdata/5_input +13 -0
  27. data/laser.gemspec +382 -0
  28. data/lib/laser.rb +98 -0
  29. data/lib/laser/analysis/annotations.rb +95 -0
  30. data/lib/laser/analysis/annotations/annotation_config.yaml +3 -0
  31. data/lib/laser/analysis/annotations/comment_attachment_annotation.rb +66 -0
  32. data/lib/laser/analysis/annotations/node_pointers_annotation.rb +36 -0
  33. data/lib/laser/analysis/annotations/runtime_annotation.rb +55 -0
  34. data/lib/laser/analysis/argument_expansion.rb +132 -0
  35. data/lib/laser/analysis/arity.rb +34 -0
  36. data/lib/laser/analysis/bindings.rb +144 -0
  37. data/lib/laser/analysis/bootstrap/bootstrap.rb +298 -0
  38. data/lib/laser/analysis/bootstrap/laser_class.rb +106 -0
  39. data/lib/laser/analysis/bootstrap/laser_method.rb +255 -0
  40. data/lib/laser/analysis/bootstrap/laser_module.rb +403 -0
  41. data/lib/laser/analysis/bootstrap/laser_module_copy.rb +74 -0
  42. data/lib/laser/analysis/bootstrap/laser_object.rb +69 -0
  43. data/lib/laser/analysis/bootstrap/laser_proc.rb +150 -0
  44. data/lib/laser/analysis/bootstrap/laser_singleton_class.rb +44 -0
  45. data/lib/laser/analysis/comments.rb +35 -0
  46. data/lib/laser/analysis/control_flow.rb +28 -0
  47. data/lib/laser/analysis/control_flow/alias_analysis.rb +31 -0
  48. data/lib/laser/analysis/control_flow/basic_block.rb +105 -0
  49. data/lib/laser/analysis/control_flow/cfg_builder.rb +2505 -0
  50. data/lib/laser/analysis/control_flow/cfg_instruction.rb +190 -0
  51. data/lib/laser/analysis/control_flow/constant_propagation.rb +742 -0
  52. data/lib/laser/analysis/control_flow/control_flow_graph.rb +370 -0
  53. data/lib/laser/analysis/control_flow/lifetime_analysis.rb +91 -0
  54. data/lib/laser/analysis/control_flow/method_call_search.rb +26 -0
  55. data/lib/laser/analysis/control_flow/raise_properties.rb +25 -0
  56. data/lib/laser/analysis/control_flow/simulation.rb +385 -0
  57. data/lib/laser/analysis/control_flow/static_single_assignment.rb +185 -0
  58. data/lib/laser/analysis/control_flow/unreachability_analysis.rb +57 -0
  59. data/lib/laser/analysis/control_flow/unused_variables.rb +91 -0
  60. data/lib/laser/analysis/control_flow/yield_properties.rb +103 -0
  61. data/lib/laser/analysis/errors.rb +131 -0
  62. data/lib/laser/analysis/laser_utils.rb +18 -0
  63. data/lib/laser/analysis/lexical_analysis.rb +172 -0
  64. data/lib/laser/analysis/method_call.rb +68 -0
  65. data/lib/laser/analysis/protocol_registry.rb +30 -0
  66. data/lib/laser/analysis/scope.rb +118 -0
  67. data/lib/laser/analysis/sexp.rb +159 -0
  68. data/lib/laser/analysis/sexp_analysis.rb +40 -0
  69. data/lib/laser/analysis/sexp_extensions/constant_extraction.rb +115 -0
  70. data/lib/laser/analysis/sexp_extensions/source_location.rb +164 -0
  71. data/lib/laser/analysis/sexp_extensions/type_inference.rb +47 -0
  72. data/lib/laser/analysis/signature.rb +76 -0
  73. data/lib/laser/analysis/special_methods/send.rb +67 -0
  74. data/lib/laser/analysis/unused_methods.rb +21 -0
  75. data/lib/laser/analysis/visitor.rb +141 -0
  76. data/lib/laser/annotation_parser/annotations.treetop +126 -0
  77. data/lib/laser/annotation_parser/annotations_parser.rb +748 -0
  78. data/lib/laser/annotation_parser/class_annotations.treetop +82 -0
  79. data/lib/laser/annotation_parser/class_annotations_parser.rb +654 -0
  80. data/lib/laser/annotation_parser/overload.treetop +24 -0
  81. data/lib/laser/annotation_parser/overload_parser.rb +167 -0
  82. data/lib/laser/annotation_parser/parsers.rb +6 -0
  83. data/lib/laser/annotation_parser/structural.treetop +37 -0
  84. data/lib/laser/annotation_parser/structural_parser.rb +406 -0
  85. data/lib/laser/annotation_parser/useful_parsers.treetop +47 -0
  86. data/lib/laser/annotation_parser/useful_parsers_parser.rb +674 -0
  87. data/lib/laser/rake/task.rb +46 -0
  88. data/lib/laser/runner.rb +189 -0
  89. data/lib/laser/scanner.rb +169 -0
  90. data/lib/laser/standard_library/_thread.rb +110 -0
  91. data/lib/laser/standard_library/abbrev.rb +103 -0
  92. data/lib/laser/standard_library/array.rb +418 -0
  93. data/lib/laser/standard_library/base64.rb +91 -0
  94. data/lib/laser/standard_library/basic_object.rb +55 -0
  95. data/lib/laser/standard_library/benchmark.rb +556 -0
  96. data/lib/laser/standard_library/bignum.rb +185 -0
  97. data/lib/laser/standard_library/cgi.rb +275 -0
  98. data/lib/laser/standard_library/cgi/cookie.rb +147 -0
  99. data/lib/laser/standard_library/cgi/core.rb +791 -0
  100. data/lib/laser/standard_library/cgi/html.rb +1021 -0
  101. data/lib/laser/standard_library/cgi/session.rb +537 -0
  102. data/lib/laser/standard_library/cgi/session/pstore.rb +111 -0
  103. data/lib/laser/standard_library/cgi/util.rb +188 -0
  104. data/lib/laser/standard_library/class_definitions.rb +333 -0
  105. data/lib/laser/standard_library/comparable.rb +125 -0
  106. data/lib/laser/standard_library/complex.rb +162 -0
  107. data/lib/laser/standard_library/enumerable.rb +178 -0
  108. data/lib/laser/standard_library/exceptions.rb +135 -0
  109. data/lib/laser/standard_library/fixnum.rb +188 -0
  110. data/lib/laser/standard_library/float.rb +180 -0
  111. data/lib/laser/standard_library/hash.rb +237 -0
  112. data/lib/laser/standard_library/integer.rb +123 -0
  113. data/lib/laser/standard_library/laser_magic.rb +7 -0
  114. data/lib/laser/standard_library/nil_false_true.rb +113 -0
  115. data/lib/laser/standard_library/numbers.rb +192 -0
  116. data/lib/laser/standard_library/proc.rb +31 -0
  117. data/lib/laser/standard_library/set.rb +1348 -0
  118. data/lib/laser/standard_library/string.rb +666 -0
  119. data/lib/laser/standard_library/stringio.rb +2 -0
  120. data/lib/laser/standard_library/symbol.rb +125 -0
  121. data/lib/laser/standard_library/tsort.rb +242 -0
  122. data/lib/laser/support/acts_as_struct.rb +66 -0
  123. data/lib/laser/support/frequency.rb +55 -0
  124. data/lib/laser/support/inheritable_attributes.rb +145 -0
  125. data/lib/laser/support/module_extensions.rb +94 -0
  126. data/lib/laser/support/placeholder_object.rb +13 -0
  127. data/lib/laser/third_party/rgl/adjacency.rb +221 -0
  128. data/lib/laser/third_party/rgl/base.rb +228 -0
  129. data/lib/laser/third_party/rgl/bidirectional.rb +39 -0
  130. data/lib/laser/third_party/rgl/condensation.rb +47 -0
  131. data/lib/laser/third_party/rgl/connected_components.rb +138 -0
  132. data/lib/laser/third_party/rgl/control_flow.rb +170 -0
  133. data/lib/laser/third_party/rgl/depth_first_spanning_tree.rb +37 -0
  134. data/lib/laser/third_party/rgl/dominators.rb +124 -0
  135. data/lib/laser/third_party/rgl/dot.rb +93 -0
  136. data/lib/laser/third_party/rgl/graphxml.rb +51 -0
  137. data/lib/laser/third_party/rgl/implicit.rb +174 -0
  138. data/lib/laser/third_party/rgl/mutable.rb +117 -0
  139. data/lib/laser/third_party/rgl/rdot.rb +445 -0
  140. data/lib/laser/third_party/rgl/topsort.rb +72 -0
  141. data/lib/laser/third_party/rgl/transitivity.rb +180 -0
  142. data/lib/laser/third_party/rgl/traversal.rb +348 -0
  143. data/lib/laser/types/types.rb +433 -0
  144. data/lib/laser/version.rb +14 -0
  145. data/lib/laser/warning.rb +149 -0
  146. data/lib/laser/warning_sets/default.yml +13 -0
  147. data/lib/laser/warnings/assignment_in_condition.rb +20 -0
  148. data/lib/laser/warnings/comment_spacing.rb +31 -0
  149. data/lib/laser/warnings/extra_blank_lines.rb +30 -0
  150. data/lib/laser/warnings/extra_whitespace.rb +16 -0
  151. data/lib/laser/warnings/hash_symbol_18_warning.rb +63 -0
  152. data/lib/laser/warnings/hash_symbol_19_warning.rb +29 -0
  153. data/lib/laser/warnings/line_length.rb +115 -0
  154. data/lib/laser/warnings/misaligned_unindentation.rb +17 -0
  155. data/lib/laser/warnings/operator_spacing.rb +68 -0
  156. data/lib/laser/warnings/parens_on_declaration.rb +30 -0
  157. data/lib/laser/warnings/rescue_exception.rb +42 -0
  158. data/lib/laser/warnings/semicolon.rb +25 -0
  159. data/lib/laser/warnings/sexp_errors.rb +24 -0
  160. data/lib/laser/warnings/uncalled_method_warning.rb +7 -0
  161. data/lib/laser/warnings/useless_double_quotes.rb +38 -0
  162. data/spec/analysis_specs/annotations_spec.rb +47 -0
  163. data/spec/analysis_specs/annotations_specs/comment_attachment_spec.rb +68 -0
  164. data/spec/analysis_specs/annotations_specs/node_pointers_annotation_spec.rb +90 -0
  165. data/spec/analysis_specs/annotations_specs/runtime_annotation_spec.rb +135 -0
  166. data/spec/analysis_specs/annotations_specs/spec_helper.rb +33 -0
  167. data/spec/analysis_specs/argument_expansion_spec.rb +113 -0
  168. data/spec/analysis_specs/bindings_spec.rb +36 -0
  169. data/spec/analysis_specs/comment_spec.rb +93 -0
  170. data/spec/analysis_specs/control_flow_specs/cfg_instruction_spec.rb +111 -0
  171. data/spec/analysis_specs/control_flow_specs/constant_propagation_spec.rb +560 -0
  172. data/spec/analysis_specs/control_flow_specs/control_flow_graph_spec.rb +5 -0
  173. data/spec/analysis_specs/control_flow_specs/raise_properties_spec.rb +310 -0
  174. data/spec/analysis_specs/control_flow_specs/raise_type_inference_spec.rb +301 -0
  175. data/spec/analysis_specs/control_flow_specs/return_type_inference_spec.rb +431 -0
  176. data/spec/analysis_specs/control_flow_specs/simulation_spec.rb +158 -0
  177. data/spec/analysis_specs/control_flow_specs/spec_helper.rb +110 -0
  178. data/spec/analysis_specs/control_flow_specs/tuple_misuse_inference_spec.rb +125 -0
  179. data/spec/analysis_specs/control_flow_specs/unreachability_analysis_spec.rb +76 -0
  180. data/spec/analysis_specs/control_flow_specs/unused_variable_spec.rb +99 -0
  181. data/spec/analysis_specs/control_flow_specs/yield_properties_spec.rb +372 -0
  182. data/spec/analysis_specs/error_spec.rb +30 -0
  183. data/spec/analysis_specs/laser_class_spec.rb +322 -0
  184. data/spec/analysis_specs/lexical_analysis_spec.rb +184 -0
  185. data/spec/analysis_specs/protocol_registry_spec.rb +63 -0
  186. data/spec/analysis_specs/scope_annotation_spec.rb +1013 -0
  187. data/spec/analysis_specs/scope_spec.rb +126 -0
  188. data/spec/analysis_specs/sexp_analysis_spec.rb +30 -0
  189. data/spec/analysis_specs/sexp_extension_specs/constant_extraction_spec.rb +309 -0
  190. data/spec/analysis_specs/sexp_extension_specs/source_location_spec.rb +231 -0
  191. data/spec/analysis_specs/sexp_extension_specs/spec_helper.rb +1 -0
  192. data/spec/analysis_specs/sexp_extension_specs/type_inference_spec.rb +252 -0
  193. data/spec/analysis_specs/sexp_spec.rb +167 -0
  194. data/spec/analysis_specs/spec_helper.rb +27 -0
  195. data/spec/analysis_specs/unused_methods_spec.rb +65 -0
  196. data/spec/analysis_specs/visitor_spec.rb +64 -0
  197. data/spec/annotation_parser_specs/annotations_parser_spec.rb +89 -0
  198. data/spec/annotation_parser_specs/class_annotation_parser_spec.rb +120 -0
  199. data/spec/annotation_parser_specs/overload_parser_spec.rb +39 -0
  200. data/spec/annotation_parser_specs/parsers_spec.rb +14 -0
  201. data/spec/annotation_parser_specs/spec_helper.rb +1 -0
  202. data/spec/annotation_parser_specs/structural_parser_spec.rb +67 -0
  203. data/spec/laser_spec.rb +14 -0
  204. data/spec/rake_specs/spec_helper.rb +1 -0
  205. data/spec/rake_specs/task_spec.rb +67 -0
  206. data/spec/runner_spec.rb +207 -0
  207. data/spec/scanner_spec.rb +75 -0
  208. data/spec/spec_helper.rb +121 -0
  209. data/spec/standard_library/exceptions_spec.rb +19 -0
  210. data/spec/standard_library/globals_spec.rb +14 -0
  211. data/spec/standard_library/set_spec.rb +31 -0
  212. data/spec/standard_library/spec_helper.rb +1 -0
  213. data/spec/standard_library/standard_library_spec.rb +302 -0
  214. data/spec/support_specs/acts_as_struct_spec.rb +94 -0
  215. data/spec/support_specs/frequency_spec.rb +23 -0
  216. data/spec/support_specs/module_extensions_spec.rb +117 -0
  217. data/spec/support_specs/spec_helper.rb +1 -0
  218. data/spec/type_specs/spec_helper.rb +1 -0
  219. data/spec/type_specs/types_spec.rb +133 -0
  220. data/spec/warning_spec.rb +95 -0
  221. data/spec/warning_specs/assignment_in_condition_spec.rb +68 -0
  222. data/spec/warning_specs/comment_spacing_spec.rb +65 -0
  223. data/spec/warning_specs/extra_blank_lines_spec.rb +70 -0
  224. data/spec/warning_specs/extra_whitespace_spec.rb +33 -0
  225. data/spec/warning_specs/hash_symbol_18_warning_spec.rb +89 -0
  226. data/spec/warning_specs/hash_symbol_19_warning_spec.rb +63 -0
  227. data/spec/warning_specs/line_length_spec.rb +173 -0
  228. data/spec/warning_specs/misaligned_unindentation_spec.rb +35 -0
  229. data/spec/warning_specs/operator_spacing_spec.rb +104 -0
  230. data/spec/warning_specs/parens_on_declaration_spec.rb +57 -0
  231. data/spec/warning_specs/rescue_exception_spec.rb +105 -0
  232. data/spec/warning_specs/semicolon_spec.rb +58 -0
  233. data/spec/warning_specs/spec_helper.rb +1 -0
  234. data/spec/warning_specs/useless_double_quotes_spec.rb +74 -0
  235. data/status_reports/2010/12/2010-12-14.md +163 -0
  236. data/status_reports/2010/12/2010-12-23.md +298 -0
  237. data/status_reports/2010/12/2010-12-24.md +6 -0
  238. data/test/third_party_tests/rgl_tests/TestComponents.rb +65 -0
  239. data/test/third_party_tests/rgl_tests/TestCycles.rb +61 -0
  240. data/test/third_party_tests/rgl_tests/TestDirectedGraph.rb +125 -0
  241. data/test/third_party_tests/rgl_tests/TestDot.rb +18 -0
  242. data/test/third_party_tests/rgl_tests/TestEdge.rb +34 -0
  243. data/test/third_party_tests/rgl_tests/TestGraph.rb +71 -0
  244. data/test/third_party_tests/rgl_tests/TestGraphXML.rb +57 -0
  245. data/test/third_party_tests/rgl_tests/TestImplicit.rb +52 -0
  246. data/test/third_party_tests/rgl_tests/TestRdot.rb +863 -0
  247. data/test/third_party_tests/rgl_tests/TestTransitivity.rb +129 -0
  248. data/test/third_party_tests/rgl_tests/TestTraversal.rb +220 -0
  249. data/test/third_party_tests/rgl_tests/TestUnDirectedGraph.rb +102 -0
  250. data/test/third_party_tests/rgl_tests/examples/north/Graph.log +128 -0
  251. data/test/third_party_tests/rgl_tests/examples/north/g.10.0.graphml +28 -0
  252. data/test/third_party_tests/rgl_tests/examples/north/g.10.1.graphml +28 -0
  253. data/test/third_party_tests/rgl_tests/examples/north/g.10.11.graphml +31 -0
  254. data/test/third_party_tests/rgl_tests/examples/north/g.10.12.graphml +27 -0
  255. data/test/third_party_tests/rgl_tests/examples/north/g.10.13.graphml +27 -0
  256. data/test/third_party_tests/rgl_tests/examples/north/g.10.14.graphml +27 -0
  257. data/test/third_party_tests/rgl_tests/examples/north/g.10.15.graphml +26 -0
  258. data/test/third_party_tests/rgl_tests/examples/north/g.10.16.graphml +26 -0
  259. data/test/third_party_tests/rgl_tests/examples/north/g.10.17.graphml +26 -0
  260. data/test/third_party_tests/rgl_tests/examples/north/g.10.19.graphml +37 -0
  261. data/test/third_party_tests/rgl_tests/examples/north/g.10.2.graphml +28 -0
  262. data/test/third_party_tests/rgl_tests/examples/north/g.10.20.graphml +38 -0
  263. data/test/third_party_tests/rgl_tests/examples/north/g.10.22.graphml +43 -0
  264. data/test/third_party_tests/rgl_tests/examples/north/g.10.24.graphml +30 -0
  265. data/test/third_party_tests/rgl_tests/examples/north/g.10.25.graphml +45 -0
  266. data/test/third_party_tests/rgl_tests/examples/north/g.10.27.graphml +38 -0
  267. data/test/third_party_tests/rgl_tests/examples/north/g.10.28.graphml +30 -0
  268. data/test/third_party_tests/rgl_tests/examples/north/g.10.29.graphml +38 -0
  269. data/test/third_party_tests/rgl_tests/examples/north/g.10.3.graphml +26 -0
  270. data/test/third_party_tests/rgl_tests/examples/north/g.10.30.graphml +34 -0
  271. data/test/third_party_tests/rgl_tests/examples/north/g.10.31.graphml +42 -0
  272. data/test/third_party_tests/rgl_tests/examples/north/g.10.34.graphml +42 -0
  273. data/test/third_party_tests/rgl_tests/examples/north/g.10.37.graphml +28 -0
  274. data/test/third_party_tests/rgl_tests/examples/north/g.10.38.graphml +38 -0
  275. data/test/third_party_tests/rgl_tests/examples/north/g.10.39.graphml +36 -0
  276. data/test/third_party_tests/rgl_tests/examples/north/g.10.4.graphml +26 -0
  277. data/test/third_party_tests/rgl_tests/examples/north/g.10.40.graphml +37 -0
  278. data/test/third_party_tests/rgl_tests/examples/north/g.10.41.graphml +37 -0
  279. data/test/third_party_tests/rgl_tests/examples/north/g.10.42.graphml +26 -0
  280. data/test/third_party_tests/rgl_tests/examples/north/g.10.45.graphml +28 -0
  281. data/test/third_party_tests/rgl_tests/examples/north/g.10.46.graphml +32 -0
  282. data/test/third_party_tests/rgl_tests/examples/north/g.10.5.graphml +31 -0
  283. data/test/third_party_tests/rgl_tests/examples/north/g.10.50.graphml +30 -0
  284. data/test/third_party_tests/rgl_tests/examples/north/g.10.56.graphml +29 -0
  285. data/test/third_party_tests/rgl_tests/examples/north/g.10.57.graphml +32 -0
  286. data/test/third_party_tests/rgl_tests/examples/north/g.10.58.graphml +32 -0
  287. data/test/third_party_tests/rgl_tests/examples/north/g.10.6.graphml +26 -0
  288. data/test/third_party_tests/rgl_tests/examples/north/g.10.60.graphml +32 -0
  289. data/test/third_party_tests/rgl_tests/examples/north/g.10.61.graphml +34 -0
  290. data/test/third_party_tests/rgl_tests/examples/north/g.10.62.graphml +34 -0
  291. data/test/third_party_tests/rgl_tests/examples/north/g.10.68.graphml +30 -0
  292. data/test/third_party_tests/rgl_tests/examples/north/g.10.69.graphml +32 -0
  293. data/test/third_party_tests/rgl_tests/examples/north/g.10.7.graphml +29 -0
  294. data/test/third_party_tests/rgl_tests/examples/north/g.10.70.graphml +26 -0
  295. data/test/third_party_tests/rgl_tests/examples/north/g.10.71.graphml +27 -0
  296. data/test/third_party_tests/rgl_tests/examples/north/g.10.72.graphml +28 -0
  297. data/test/third_party_tests/rgl_tests/examples/north/g.10.74.graphml +29 -0
  298. data/test/third_party_tests/rgl_tests/examples/north/g.10.75.graphml +29 -0
  299. data/test/third_party_tests/rgl_tests/examples/north/g.10.78.graphml +27 -0
  300. data/test/third_party_tests/rgl_tests/examples/north/g.10.79.graphml +34 -0
  301. data/test/third_party_tests/rgl_tests/examples/north/g.10.8.graphml +29 -0
  302. data/test/third_party_tests/rgl_tests/examples/north/g.10.80.graphml +34 -0
  303. data/test/third_party_tests/rgl_tests/examples/north/g.10.82.graphml +35 -0
  304. data/test/third_party_tests/rgl_tests/examples/north/g.10.83.graphml +32 -0
  305. data/test/third_party_tests/rgl_tests/examples/north/g.10.85.graphml +34 -0
  306. data/test/third_party_tests/rgl_tests/examples/north/g.10.86.graphml +34 -0
  307. data/test/third_party_tests/rgl_tests/examples/north/g.10.88.graphml +37 -0
  308. data/test/third_party_tests/rgl_tests/examples/north/g.10.89.graphml +29 -0
  309. data/test/third_party_tests/rgl_tests/examples/north/g.10.9.graphml +26 -0
  310. data/test/third_party_tests/rgl_tests/examples/north/g.10.90.graphml +32 -0
  311. data/test/third_party_tests/rgl_tests/examples/north/g.10.91.graphml +31 -0
  312. data/test/third_party_tests/rgl_tests/examples/north/g.10.92.graphml +26 -0
  313. data/test/third_party_tests/rgl_tests/examples/north/g.10.93.graphml +32 -0
  314. data/test/third_party_tests/rgl_tests/examples/north/g.10.94.graphml +34 -0
  315. data/test/third_party_tests/rgl_tests/examples/north/g.12.8.graphml +40 -0
  316. data/test/third_party_tests/rgl_tests/examples/north/g.14.9.graphml +36 -0
  317. data/test/third_party_tests/rgl_tests/test_helper.rb +7 -0
  318. data/test/third_party_tests/test_inheritable_attributes.rb +187 -0
  319. metadata +470 -0
@@ -0,0 +1,174 @@
1
+ # implicit.rb
2
+ #
3
+ # This file contains the definition of the class RGL::ImplicitGraph, which
4
+ # defines vertex and edge iterators using blocks (which again call blocks).
5
+ #
6
+ # An ImplicitGraph provides a handy way to define graphs on the fly, using two
7
+ # blocks for the two iterators defining a graph. A directed cyclic graph,
8
+ # with five vertices can be created as follows:
9
+ #
10
+ # g = RGL::ImplicitGraph.new { |g|
11
+ # g.vertex_iterator { |b| 0.upto(4,&b) }
12
+ # g.adjacent_iterator { |x, b| b.call((x+1)%5) }
13
+ # g.directed = true
14
+ # }
15
+ #
16
+ # g.to_s => "(0-1)(1-2)(2-3)(3-4)(4-0)"
17
+ #
18
+ # Other examples are given by the methods vertices_filtered_by and
19
+ # edges_filtered_by, which can be applied to any graph.
20
+
21
+ require 'laser/third_party/rgl/base'
22
+
23
+ module RGL
24
+
25
+ class ImplicitGraph
26
+
27
+ include Graph
28
+
29
+ attr_writer :directed
30
+
31
+ EMPTY_VERTEX_ITERATOR = proc { |b| }
32
+ EMPTY_NEIGHBOR_ITERATOR = proc { |x, b| }
33
+
34
+ # Create a new ImplicitGraph, which is empty by default. The caller should
35
+ # configure the graph using vertex and neighbor iterators. If the graph is
36
+ # directed, the client should set _directed_ to true. The default value
37
+ # for _directed_ is false.
38
+
39
+ def initialize
40
+ @directed = false
41
+ @vertex_iterator = EMPTY_VERTEX_ITERATOR
42
+ @adjacent_iterator = EMPTY_NEIGHBOR_ITERATOR
43
+ yield self if block_given? # Let client overwrite defaults.
44
+ end
45
+
46
+ # Returns the value of @directed.
47
+
48
+ def directed?
49
+ @directed
50
+ end
51
+
52
+ def each_vertex (&block) # :nodoc:
53
+ @vertex_iterator.call(block)
54
+ end
55
+
56
+ def each_adjacent (v, &block) # :nodoc:
57
+ @adjacent_iterator.call(v, block)
58
+ end
59
+
60
+ def each_edge (&block) # :nodoc:
61
+ if defined? @edge_iterator
62
+ @edge_iterator.call(block)
63
+ else
64
+ super # use default implementation
65
+ end
66
+ end
67
+
68
+ # Sets the vertex_iterator to _block_,
69
+ # which must be a block of one parameter
70
+ # which again is the block called by each_vertex.
71
+
72
+ def vertex_iterator (&block)
73
+ @vertex_iterator = block
74
+ end
75
+
76
+ # Sets the adjacent_iterator to _block_,
77
+ # which must be a block of two parameters:
78
+ #
79
+ # The first parameter is the vertex the neighbors of which are to be
80
+ # traversed.
81
+ #
82
+ # The second is the block which will be called for each neighbor
83
+ # of this vertex.
84
+
85
+ def adjacent_iterator (&block)
86
+ @adjacent_iterator = block
87
+ end
88
+
89
+ # Sets the edge_iterator to _block_, which must be a block of two
90
+ # parameters: The first parameter is the source of the edges; the
91
+ # second is the target of the edge.
92
+
93
+ def edge_iterator (&block)
94
+ @edge_iterator = block
95
+ end
96
+
97
+ end # class ImplicitGraph
98
+
99
+
100
+ module Graph
101
+
102
+ # ---
103
+ # === Graph adaptors
104
+ #
105
+ # Return a new ImplicitGraph which has as vertices all vertices of the
106
+ # receiver which satisfy the predicate _filter_.
107
+ #
108
+ # The methods provides similar functionaty as the BGL graph adapter
109
+ # filtered_graph (see BOOST_DOC/filtered_graph.html).
110
+ #
111
+ # ==== Example
112
+ #
113
+ # def complete (n)
114
+ # set = n.integer? ? (1..n) : n
115
+ # RGL::ImplicitGraph.new { |g|
116
+ # g.vertex_iterator { |b| set.each(&b) }
117
+ # g.adjacent_iterator { |x, b|
118
+ # set.each { |y| b.call(y) unless x == y }
119
+ # }
120
+ # }
121
+ # end
122
+ #
123
+ # complete(4).to_s => "(1=2)(1=3)(1=4)(2=3)(2=4)(3=4)"
124
+ # complete(4).vertices_filtered_by {|v| v != 4}.to_s => "(1=2)(1=3)(2=3)"
125
+
126
+ def vertices_filtered_by (&filter)
127
+ implicit_graph { |g|
128
+ g.vertex_iterator { |b|
129
+ self.each_vertex { |v| b.call(v) if filter.call(v) }
130
+ }
131
+ g.adjacent_iterator { |v, b|
132
+ self.each_adjacent(v) { |u| b.call(u) if filter.call(u) }
133
+ }
134
+ }
135
+ end
136
+
137
+ # Return a new ImplicitGraph which has as edges all edges of the receiver
138
+ # which satisfy the predicate _filter_ (a block with two parameters).
139
+ #
140
+ # ==== Example
141
+ #
142
+ # g = complete(7).edges_filtered_by {|u,v| u+v == 7}
143
+ # g.to_s => "(1=6)(2=5)(3=4)"
144
+ # g.vertices => [1, 2, 3, 4, 5, 6, 7]
145
+
146
+ def edges_filtered_by (&filter)
147
+ implicit_graph { |g|
148
+ g.adjacent_iterator { |v, b|
149
+ self.each_adjacent(v) { |u|
150
+ b.call(u) if filter.call(v, u)
151
+ }
152
+ }
153
+ g.edge_iterator { |b|
154
+ self.each_edge { |u,v| b.call(u, v) if filter.call(u, v) }
155
+ }
156
+ }
157
+ end
158
+
159
+ # Return a new ImplicitGraph which is isomorphic (i.e. has same edges and
160
+ # vertices) to the receiver. It is a shortcut, also used by
161
+ # edges_filtered_by and vertices_filtered_by.
162
+
163
+ def implicit_graph
164
+ result = ImplicitGraph.new { |g|
165
+ g.vertex_iterator { |b| self.each_vertex(&b) }
166
+ g.adjacent_iterator { |v, b| self.each_adjacent(v, &b) }
167
+ g.directed = self.directed?
168
+ }
169
+ yield result if block_given? # let client overwrite defaults
170
+ result
171
+ end
172
+
173
+ end # module Graph
174
+ end # module RGL
@@ -0,0 +1,117 @@
1
+ # mutable.rb
2
+
3
+ require 'laser/third_party/rgl/base'
4
+
5
+ module RGL
6
+
7
+ # A MutableGraph can be changed via the addition or removal of edges and
8
+ # vertices.
9
+ module MutableGraph
10
+
11
+ include Graph
12
+
13
+ # Add a new vertex _v_ to the graph. If the vertex is already in the
14
+ # graph (tested via eql?), the method does nothing.
15
+
16
+ def add_vertex (v)
17
+ raise NotImplementedError
18
+ end
19
+
20
+ # Inserts the edge (u,v) into the graph.
21
+ #
22
+ # Note that for undirected graphs, (u,v) is the same edge as (v,u), so
23
+ # after a call to the function add_edge(), this implies that edge (u,v)
24
+ # will appear in the out-edges of u and (u,v) (or equivalently (v,u))
25
+ # will appear in the out-edges of v. Put another way, v will be adjacent
26
+ # to u and u will be adjacent to v.
27
+
28
+ def add_edge (u, v)
29
+ raise NotImplementedError
30
+ end
31
+
32
+ # Add all objects in _a_ to the vertex set.
33
+
34
+ def add_vertices (*a)
35
+ a.each { |v| add_vertex v }
36
+ end
37
+
38
+ # Add all edges in the _edges_ array to the edge set. Elements of the
39
+ # array can be both two-element arrays or instances of DirectedEdge or
40
+ # UnDirectedEdge.
41
+
42
+ def add_edges (*edges)
43
+ edges.each { |edge| add_edge(edge[0], edge[1]) }
44
+ end
45
+
46
+ # Add the graph to the current graph. All vertices in the other graph
47
+ # are added, as are all edges.
48
+
49
+ def add_graph(graph)
50
+ add_vertices(*graph.vertices)
51
+ add_edges(*graph.edges)
52
+ end
53
+
54
+ # Adds all the given graphs to the current graph. See #add_graph.
55
+
56
+ def add_graphs(*graphs)
57
+ graphs.each { |graph| add_graph graph }
58
+ end
59
+
60
+ # Remove u from the vertex set of the graph. All edges whose target is
61
+ # _v_ are also removed from the edge set of the graph.
62
+ #
63
+ # Postcondition: num_vertices is one less, _v_ no longer appears in the
64
+ # vertex set of the graph, and there no edge with source or target _v_.
65
+
66
+ def remove_vertex (v)
67
+ raise NotImplementedError
68
+ end
69
+
70
+ # Remove the edge (u,v) from the graph. If the graph allows parallel
71
+ # edges, this removes all occurrences of (u,v).
72
+ #
73
+ # Precondition: u and v are vertices in the graph.
74
+ # Postcondition: (u,v) is no longer in the edge set for g.
75
+
76
+ def remove_edge (u, v)
77
+ raise NotImplementedError
78
+ end
79
+
80
+ # Remove all vertices specified by the array a from the graph by calling
81
+ # remove_vertex.
82
+
83
+ def remove_vertices (*a)
84
+ a.each { |v| remove_vertex v }
85
+ end
86
+
87
+ # Returns all minimum cycles that pass through a give vertex.
88
+ # The format is an Array of cycles, with each cycle being an Array
89
+ # of vertices in the cycle.
90
+ def cycles_with_vertex(vertex)
91
+ cycles_with_vertex_helper(vertex, vertex, [])
92
+ end
93
+
94
+ protected
95
+ def cycles_with_vertex_helper(vertex, start, visited) #:nodoc:
96
+ adjacent_vertices(start).reject {|x| visited.include?(x)}.inject([]) do |acc, adj|
97
+ local_visited = Array.new(visited) << adj
98
+ acc << local_visited if (adj==vertex)
99
+ acc = acc + cycles_with_vertex_helper(vertex,adj,local_visited)
100
+ end
101
+ end
102
+
103
+ public
104
+ # Returns an array of all minimum cycles in a graph
105
+ #
106
+ # This is not an efficient implementation O(n^4) and could
107
+ # be done using Minimum Spanning Trees. Hint. Hint.
108
+ def cycles
109
+ g = self.clone
110
+ self.inject([]) do |acc, v|
111
+ acc = acc.concat(g.cycles_with_vertex(v))
112
+ g.remove_vertex(v); acc
113
+ end
114
+ end
115
+
116
+ end # module MutableGraph
117
+ end # module RGL
@@ -0,0 +1,445 @@
1
+ # This is a modified version of dot.rb from Dave Thomas's rdoc project. I
2
+ # renamed it to rdot.rb to avoid collision with an installed rdoc/dot.
3
+ #
4
+ # It also supports undirected edges.
5
+
6
+ module RGL; module DOT
7
+
8
+ # options for node declaration
9
+
10
+ NODE_OPTS = [
11
+ # attributes due to
12
+ # http://www.graphviz.org/Documentation/dotguide.pdf
13
+ # February 23, 2008
14
+ 'color', # default: black; node shape color
15
+ 'comment', # any string (format-dependent)
16
+ 'distortion', # default: 0.0; node distortion for shape=polygon
17
+ 'fillcolor', # default: lightgrey/black; node fill color
18
+ 'fixedsize', # default: false; label text has no affect on node size
19
+ 'fontcolor', # default: black; type face color
20
+ 'fontname', # default: Times-Roman; font family
21
+ 'fontsize', #default: 14; point size of label
22
+ 'group', # name of node's group
23
+ 'height', # default: .5; height in inches
24
+ 'label', # default: node name; any string
25
+ 'layer', # default: overlay range; all, id or id:id
26
+ 'orientation', # dafault: 0.0; node rotation angle
27
+ 'peripheries', # shape-dependent number of node boundaries
28
+ 'regular', # default: false; force polygon to be regular
29
+ 'shape', # default: ellipse; node shape; see Section 2.1 and Appendix E
30
+ 'shapefile', # external EPSF or SVG custom shape file
31
+ 'sides', # default: 4; number of sides for shape=polygon
32
+ 'skew' , # default: 0.0; skewing of node for shape=polygon
33
+ 'style', # graphics options, e.g. bold, dotted, filled; cf. Section 2.3
34
+ 'URL', # URL associated with node (format-dependent)
35
+ 'width', # default: .75; width in inches
36
+ 'z', #default: 0.0; z coordinate for VRML output
37
+
38
+ # maintained for backward compatibility or rdot internal
39
+ 'bottomlabel', # auxiliary label for nodes of shape M*
40
+ 'bgcolor',
41
+ 'rank',
42
+ 'toplabel' # auxiliary label for nodes of shape M*
43
+ ]
44
+
45
+ # options for edge declaration
46
+
47
+ EDGE_OPTS = [
48
+ 'arrowhead', # default: normal; style of arrowhead at head end
49
+ 'arrowsize', # default: 1.0; scaling factor for arrowheads
50
+ 'arrowtail', # default: normal; style of arrowhead at tail end
51
+ 'color', # default: black; edge stroke color
52
+ 'comment', # any string (format-dependent)
53
+ 'constraint', # default: true use edge to affect node ranking
54
+ 'decorate', # if set, draws a line connecting labels with their edges
55
+ 'dir', # default: forward; forward, back, both, or none
56
+ 'fontcolor', # default: black type face color
57
+ 'fontname', # default: Times-Roman; font family
58
+ 'fontsize', # default: 14; point size of label
59
+ 'headlabel', # label placed near head of edge
60
+ 'headport', # n,ne,e,se,s,sw,w,nw
61
+ 'headURL', # URL attached to head label if output format is ismap
62
+ 'label', # edge label
63
+ 'labelangle', # default: -25.0; angle in degrees which head or tail label is rotated off edge
64
+ 'labeldistance', # default: 1.0; scaling factor for distance of head or tail label from node
65
+ 'labelfloat', # default: false; lessen constraints on edge label placement
66
+ 'labelfontcolor', # default: black; type face color for head and tail labels
67
+ 'labelfontname', # default: Times-Roman; font family for head and tail labels
68
+ 'labelfontsize', # default: 14 point size for head and tail labels
69
+ 'layer', # default: overlay range; all, id or id:id
70
+ 'lhead', # name of cluster to use as head of edge
71
+ 'ltail', # name of cluster to use as tail of edge
72
+ 'minlen', # default: 1 minimum rank distance between head and tail
73
+ 'samehead', # tag for head node; edge heads with the same tag are merged onto the same port
74
+ 'sametail', # tag for tail node; edge tails with the same tag are merged onto the same port
75
+ 'style', # graphics options, e.g. bold, dotted, filled; cf. Section 2.3
76
+ 'taillabel', # label placed near tail of edge
77
+ 'tailport', # n,ne,e,se,s,sw,w,nw
78
+ 'tailURL', # URL attached to tail label if output format is ismap
79
+ 'weight', # default: 1; integer cost of stretching an edge
80
+
81
+ # maintained for backward compatibility or rdot internal
82
+ 'id'
83
+ ]
84
+
85
+ # options for graph declaration
86
+
87
+ GRAPH_OPTS = [
88
+ 'bgcolor', # background color for drawing, plus initial fill color
89
+ 'center', # default: false; center draing on page
90
+ 'clusterrank', # default: local; may be "global" or "none"
91
+ 'color', # default: black; for clusters, outline color, and fill color if
92
+ # fillcolor not defined
93
+ 'comment', # any string (format-dependent)
94
+ 'compound', # default: false; allow edges between clusters
95
+ 'concentrate', # default: false; enables edge concentrators
96
+ 'fillcolor', # default: black; cluster fill color
97
+ 'fontcolor', # default: black; type face color
98
+ 'fontname', # default: Times-Roman; font family
99
+ 'fontpath', # list of directories to search for fonts
100
+ 'fontsize', # default: 14; point size of label
101
+ 'label', # any string
102
+ 'labeljust', # default: centered; "l" and "r" for left- and right-justified
103
+ # cluster labels, respectively
104
+ 'labelloc', # default: top; "t" and "b" for top- and bottom-justified
105
+ # cluster labels, respectively
106
+ 'layers', # id:id:id...
107
+ 'margin', # default: .5; margin included in page, inches
108
+ 'mclimit', # default: 1.0; scale factor for mincross iterations
109
+ 'nodesep', # default: .25; separation between nodes, in inches.
110
+ 'nslimit', # if set to "f", bounds network simplex iterations by
111
+ # (f)(number of nodes) when setting x-coordinates
112
+ 'nslimit1', # if set to "f", bounds network simplex iterations by
113
+ # (f)(number of nodes) when ranking nodes
114
+ 'ordering', # if "out" out edge order is preserved
115
+ 'orientation', # default: portrait; if "rotate" is not used and the value is
116
+ # "landscape", use landscape orientation
117
+ 'page', # unit of pagination, e.g. "8.5,11"
118
+ 'rank', # "same", "min", "max", "source", or "sink"
119
+ 'rankdir', # default: TB; "LR" (left to right) or "TB" (top to bottom)
120
+ 'ranksep', # default: .75; separation between ranks, in inches.
121
+ 'ratio', # approximate aspect ratio desired, "fill" or "auto"
122
+ 'samplepoints', # default: 8; number of points used to represent ellipses
123
+ # and circles on output
124
+ 'searchsize', # default: 30; maximum edges with negative cut values to check
125
+ # when looking for a minimum one during network simplex
126
+ 'size', # maximum drawing size, in inches
127
+ 'style', # graphics options, e.g. "filled" for clusters
128
+ 'URL', # URL associated with graph (format-dependent)
129
+
130
+ # maintained for backward compatibility or rdot internal
131
+ 'layerseq'
132
+ ]
133
+
134
+ # Ancestor of Edge, Node, and Graph.
135
+ class Element
136
+ attr_accessor :name, :options
137
+
138
+ def initialize (params = {}, option_list = []) # :nodoc:
139
+ @name = params['name'] ? params['name'] : nil
140
+ @options = {}
141
+ option_list.each{ |i|
142
+ @options[i] = params[i] if params[i]
143
+ }
144
+ end
145
+
146
+ private
147
+ # Returns the string given in _id_ within quotes if necessary. Special
148
+ # characters are escaped as necessary.
149
+ def quote_ID(id)
150
+ # Ensure that the ID is a string.
151
+ id = id.to_s
152
+
153
+ # Return the ID verbatim if it looks like a name, a number, or HTML.
154
+ return id if id =~ /\A([[:alpha:]_][[:alnum:]_]*|-?(\.[[:digit:]]+|[[:digit:]]+(\.[[:digit:]]*)?)|<.*>)\Z/m and id[-1] != ?\n
155
+
156
+ # Return a quoted version of the ID otherwise.
157
+ '"' + id.gsub('\\', '\\\\\\\\').gsub('"', '\\\\"') + '"'
158
+ end
159
+
160
+ # Returns the string given in _label_ within quotes if necessary. Special
161
+ # characters are escaped as necessary. Labels get special treatment in
162
+ # order to handle embedded *\n*, *\r*, and *\l* sequences which are copied
163
+ # into the new string verbatim.
164
+ def quote_label(label)
165
+ # Ensure that the label is a string.
166
+ label = label.to_s
167
+
168
+ # Return the label verbatim if it looks like a name, a number, or HTML.
169
+ return label if label =~ /\A([[:alpha:]_][[:alnum:]_]*|-?(\.[[:digit:]]+|[[:digit:]]+(\.[[:digit:]]*)?)|<.*>)\Z/m and label[-1] != ?\n
170
+
171
+ # Return a quoted version of the label otherwise.
172
+ '"' + label.split(/(\\n|\\r|\\l)/).collect do |part|
173
+ case part
174
+ when "\\n", "\\r", "\\l"
175
+ part
176
+ else
177
+ part.gsub('\\', '\\\\\\\\').gsub('"', '\\\\"').gsub("\n", '\\n')
178
+ end
179
+ end.join + '"'
180
+ end
181
+ end
182
+
183
+
184
+ # Ports are used when a Node instance has its `shape' option set to
185
+ # _record_ or _Mrecord_. Ports can be nested.
186
+ class Port
187
+ attr_accessor :name, :label, :ports
188
+
189
+ # Create a new port with either an optional name and label or a set of
190
+ # nested ports.
191
+ #
192
+ # :call-seq:
193
+ # new(name = nil, label = nil)
194
+ # new(ports)
195
+ #
196
+ # A +nil+ value for +name+ is valid; otherwise, it must be a String or it
197
+ # will be interpreted as +ports+.
198
+ def initialize (name_or_ports = nil, label = nil)
199
+ if name_or_ports.nil? or name_or_ports.kind_of?(String) then
200
+ @name = name_or_ports
201
+ @label = label
202
+ @ports = nil
203
+ else
204
+ @ports = name_or_ports
205
+ @name = nil
206
+ @label = nil
207
+ end
208
+ end
209
+
210
+ # Returns a string representation of this port. If ports is a non-empty
211
+ # Enumerable, a nested ports representation is returned; otherwise, a
212
+ # name-label representation is returned.
213
+ def to_s
214
+ if @ports.nil? or @ports.empty? then
215
+ n = (name.nil? or name.empty?) ? '' : "<#{name}>"
216
+ n + ((n.empty? or label.nil? or label.empty?) ? '' : ' ') + label.to_s
217
+ else
218
+ '{' + @ports.collect {|p| p.to_s}.join(' | ') + '}'
219
+ end
220
+ end
221
+ end
222
+
223
+ # A node representation. Edges are drawn between nodes. The rendering of a
224
+ # node depends upon the options set for it.
225
+ class Node < Element
226
+ attr_accessor :ports
227
+
228
+ # Creates a new Node with the _params_ Hash providing settings for all
229
+ # node options. The _option_list_ parameter restricts those options to the
230
+ # list of valid names it contains. The exception to this is the _ports_
231
+ # option which, if specified, must be an Enumerable containing a list of
232
+ # ports.
233
+ def initialize (params = {}, option_list = NODE_OPTS)
234
+ super(params, option_list)
235
+ @ports = params['ports'] ? params['ports'] : []
236
+ end
237
+
238
+ # Returns a string representation of this node which is consumable by the
239
+ # graphviz tools +dot+ and +neato+. The _leader_ parameter is used to indent
240
+ # every line of the returned string, and the _indent_ parameter is used to
241
+ # additionally indent nested items.
242
+ def to_s (leader = '', indent = ' ')
243
+ label_option = nil
244
+ if @options['shape'] =~ /^M?record$/ && !@ports.empty? then
245
+ # Ignore the given label option in this case since the ports should each
246
+ # provide their own name/label.
247
+ label_option = leader + indent + "#{quote_ID('label')} = #{quote_ID(@ports.collect { |port| port.to_s }.join(" | "))}"
248
+ elsif @options['label'] then
249
+ # Otherwise, use the label when given one.
250
+ label_option = leader + indent + "#{quote_ID('label')} = #{quote_label(@options['label'])}"
251
+ end
252
+
253
+ # Convert all the options except `label' and options with nil values
254
+ # straight into name = value pairs. Then toss out any resulting nil
255
+ # entries in the final array.
256
+ stringified_options = @options.collect do |name, val|
257
+ unless name == 'label' || val.nil? then
258
+ leader + indent + "#{quote_ID(name)} = #{quote_ID(val)}"
259
+ end
260
+ end.compact
261
+ # Append the specially computed label option.
262
+ stringified_options.push(label_option) unless label_option.nil?
263
+ # Join them all together.
264
+ stringified_options = stringified_options.join(",\n")
265
+
266
+ # Put it all together into a single string with indentation and return the
267
+ # result.
268
+ if stringified_options.empty? then
269
+ return leader + quote_ID(@name) unless @name.nil?
270
+ return nil
271
+ else
272
+ return leader + (@name.nil? ? '' : quote_ID(@name) + " ") + "[\n" +
273
+ stringified_options + "\n" +
274
+ leader + "]"
275
+ end
276
+ end
277
+
278
+ end # class Node
279
+
280
+ # A graph representation. Whether or not it is rendered as directed or
281
+ # undirected depends on which of the programs *dot* or *neato* is used to
282
+ # process and render the graph.
283
+ class Graph < Element
284
+
285
+ # Creates a new Graph with the _params_ Hash providing settings for all
286
+ # graph options. The _option_list_ parameter restricts those options to the
287
+ # list of valid names it contains. The exception to this is the _elements_
288
+ # option which, if specified, must be an Enumerable containing a list of
289
+ # nodes, edges, and/or subgraphs.
290
+ def initialize (params = {}, option_list = GRAPH_OPTS)
291
+ super(params, option_list)
292
+ @elements = params['elements'] ? params['elements'] : []
293
+ @dot_string = 'graph'
294
+ end
295
+
296
+ # Calls _block_ once for each node, edge, or subgraph contained by this
297
+ # graph, passing the node, edge, or subgraph to the block.
298
+ #
299
+ # :call-seq:
300
+ # graph.each_element {|element| block} -> graph
301
+ #
302
+ def each_element (&block)
303
+ @elements.each(&block)
304
+ self
305
+ end
306
+
307
+ # Adds a new node, edge, or subgraph to this graph.
308
+ #
309
+ # :call-seq:
310
+ # graph << element -> graph
311
+ #
312
+ def << (element)
313
+ @elements << element
314
+ self
315
+ end
316
+ alias :push :<<
317
+
318
+ # Removes the most recently added node, edge, or subgraph from this graph
319
+ # and returns it.
320
+ #
321
+ # :call-seq:
322
+ # graph.pop -> element
323
+ #
324
+ def pop
325
+ @elements.pop
326
+ end
327
+
328
+ # Returns a string representation of this graph which is consumable by the
329
+ # graphviz tools +dot+ and +neato+. The _leader_ parameter is used to indent
330
+ # every line of the returned string, and the _indent_ parameter is used to
331
+ # additionally indent nested items.
332
+ def to_s (leader = '', indent = ' ')
333
+ hdr = leader + @dot_string + (@name.nil? ? '' : ' ' + quote_ID(@name)) + " {\n"
334
+
335
+ options = @options.to_a.collect do |name, val|
336
+ unless val.nil? then
337
+ if name == 'label' then
338
+ leader + indent + "#{quote_ID(name)} = #{quote_label(val)}"
339
+ else
340
+ leader + indent + "#{quote_ID(name)} = #{quote_ID(val)}"
341
+ end
342
+ end
343
+ end.compact.join( "\n" )
344
+
345
+ elements = @elements.collect do |element|
346
+ element.to_s(leader + indent, indent)
347
+ end.join("\n\n")
348
+ hdr + (options.empty? ? '' : options + "\n\n") +
349
+ (elements.empty? ? '' : elements + "\n") + leader + "}"
350
+ end
351
+
352
+ end # class Graph
353
+
354
+ # A digraph is a directed graph representation which is the same as a Graph
355
+ # except that its header in dot notation has an identifier of _digraph_
356
+ # instead of _graph_.
357
+ class Digraph < Graph
358
+
359
+ # Creates a new Digraph with the _params_ Hash providing settings for all
360
+ # graph options. The _option_list_ parameter restricts those options to the
361
+ # list of valid names it contains. The exception to this is the _elements_
362
+ # option which, if specified, must be an Enumerable containing a list of
363
+ # nodes, edges, and/or subgraphs.
364
+ def initialize (params = {}, option_list = GRAPH_OPTS)
365
+ super(params, option_list)
366
+ @dot_string = 'digraph'
367
+ end
368
+
369
+ end # class Digraph
370
+
371
+ # A subgraph is a nested graph element and is the same as a Graph except
372
+ # that its header in dot notation has an identifier of _subgraph_ instead of
373
+ # _graph_.
374
+ class Subgraph < Graph
375
+
376
+ # Creates a new Subgraph with the _params_ Hash providing settings for
377
+ # all graph options. The _option_list_ parameter restricts those options to
378
+ # list of valid names it contains. The exception to this is the _elements_
379
+ # option which, if specified, must be an Enumerable containing a list of
380
+ # nodes, edges, and/or subgraphs.
381
+ def initialize (params = {}, option_list = GRAPH_OPTS)
382
+ super(params, option_list)
383
+ @dot_string = 'subgraph'
384
+ end
385
+
386
+ end # class Subgraph
387
+
388
+ # This is an undirected edge representation.
389
+ class Edge < Element
390
+
391
+ # A node or subgraph reference or instance to be used as the starting point
392
+ # for an edge.
393
+ attr_accessor :from
394
+ # A node or subgraph reference or instance to be used as the ending point
395
+ # for an edge.
396
+ attr_accessor :to
397
+
398
+ # Creates a new Edge with the _params_ Hash providing settings for all
399
+ # edge options. The _option_list_ parameter restricts those options to the
400
+ # list of valid names it contains.
401
+ def initialize (params = {}, option_list = EDGE_OPTS)
402
+ super(params, option_list)
403
+ @from = params['from'] ? params['from'] : nil
404
+ @to = params['to'] ? params['to'] : nil
405
+ end
406
+
407
+ # Returns a string representation of this edge which is consumable by the
408
+ # graphviz tools +dot+ and +neato+. The _leader_ parameter is used to indent
409
+ # every line of the returned string, and the _indent_ parameter is used to
410
+ # additionally indent nested items.
411
+ def to_s (leader = '', indent = ' ')
412
+ stringified_options = @options.collect do |name, val|
413
+ unless val.nil? then
414
+ leader + indent + "#{quote_ID(name)} = #{quote_ID(val)}"
415
+ end
416
+ end.compact.join( ",\n" )
417
+
418
+ f_s = @from || ''
419
+ t_s = @to || ''
420
+ if stringified_options.empty? then
421
+ leader + quote_ID(f_s) + ' ' + edge_link + ' ' + quote_ID(t_s)
422
+ else
423
+ leader + quote_ID(f_s) + ' ' + edge_link + ' ' + quote_ID(t_s) + " [\n" +
424
+ stringified_options + "\n" +
425
+ leader + "]"
426
+ end
427
+ end
428
+
429
+ private
430
+ def edge_link
431
+ '--'
432
+ end
433
+
434
+ end # class Edge
435
+
436
+ # A directed edge representation otherwise identical to Edge.
437
+ class DirectedEdge < Edge
438
+
439
+ private
440
+ def edge_link
441
+ '->'
442
+ end
443
+
444
+ end # class DirectedEdge
445
+ end; end # module RGL; module DOT