laser 0.7.0.pre1

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 (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