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,298 @@
1
+ # Type Annotation Grumblings
2
+
3
+ I'm trying to hammer out how I want type annotations for Ruby methods
4
+ and/or classes to work. I usually only think about methods because, well,
5
+ they're damn-near everything in Ruby.
6
+
7
+ First off, this is just for types. All other annotations will just be
8
+ using YARD's parser, straight up. I'm just gonna fork it.
9
+
10
+ I know I want to support annotations that "say" something about the type,
11
+ because my idea is that Rubyists use Ruby for its expressivity. They expect
12
+ every line to mean something, damn it. So I just don't accept that [DRuby](http://www.cs.umd.edu/projects/PL/druby/)
13
+ has this right – mainly because I can't convince *myself* to use it.
14
+
15
+ The type system has gotta have a simple – and I mean literally, closest to
16
+ the fewest characters possible – way to describe each case.
17
+
18
+ Given an expression `E`, I want the user to be able to simply tell Laser:
19
+
20
+ * `E` has class `T`.
21
+ * `E` is a subtype of `E`.
22
+ * `E` is a subclass of `E`. (Not the same as subtype. We know this by now!)
23
+ * `E` is a supertype of `E`.
24
+ * `E` is a superclass of `E`.
25
+ * `E`'s class, or one of `E`'s superclasses, includes module `M`. (Could easily piggyback off of the subclass mechanism)
26
+ * `E`'s class, or one of `E`'s superclasses, extends module `M`.
27
+ * `E`'s class is of class (using `C\+\+`/everyone else notation) `S<T>`: a type
28
+ `S` parameterized on type `T` (or any tuple of types).
29
+
30
+ Those are the easy ones. Now for something better/weirder:
31
+
32
+ ## Better Syntax for Parameterized types.
33
+
34
+ First off: which would you prefer?
35
+
36
+ # opts: CustomOptionsClass<Symbol, String>
37
+ def compute(opts=DEFAULT_OPTIONS)
38
+ end
39
+
40
+ or:
41
+
42
+ # opts: CustomOptionsClass<Symbol => String>
43
+ def compute(opts=DEFAULT_OPTIONS)
44
+ end
45
+
46
+ I prefer the latter. Oh, and as a synonym for `Hash<Symbol => String>`:
47
+
48
+ # opts: Symbol => String
49
+ def compute(opts=DEFAULT_OPTIONS)
50
+ end
51
+
52
+ Now, a function type is just a mapping from a tuple of types to a return type. So I'd like to allow both Go syntax:
53
+
54
+ # compute_proc: (String, MyLib::TreeNode) Integer
55
+
56
+ and a normal arrow syntax:
57
+
58
+ # compute_proc: (String, MyLib::TreeNode) -> Fixnum= | Bignum=
59
+
60
+ It's natural for people to group arguments together with parens and separate them with commas. They will with Laser's syntax.
61
+
62
+ ## Union Types
63
+
64
+ Crucial. Vertical bar. String | Symbol.
65
+
66
+ ## Imports? Kinda!
67
+
68
+ `E`'s class is defined in module M or one of M's submodules (or sub-submodules... the whole set of modules in M's module tree). This could be *extremely* useful to a gem author to ensure that his library's boundaries are well-defined: if I make it easy enough, a Ruby user could say "Everything in module Laser uses only top-level classes and classes defined in Laser." With a smart enough annotation system, I could make it so a user writes something like this (throwaway syntax), where "in Amp" means "was defined in ::Amp or a submodule" and "in ::!" means "defined in the top-level, and NOT a submodule." "in ::!" would likely be added by default, actually – who could write Ruby without the top level? So yeah – I'm guessing have the default argument type of course be "completely unknown," but as soon as you activate a "defined in M" annotation somewhere, it implicitly includes "in the top-level and only top-level" as an other possibility (hence the Union in the throwaway syntax).
69
+
70
+ # Laser: defaults.argument_type = in Amp | in ::!
71
+
72
+ ## Strict Unknowns
73
+
74
+ A lot of times you might not know a type (by itself or as a type parameter) but want to have it checked to be add the requirement that that type be *consistent with some other constraint across global usage*. The obvious constraint would be type compatibility or class compatibility, though the 'defined in module M' is another common one you might consider. Simple use case: marking that you return object `X` which was returned to you by a library. Who knows what class it is? You don't care, but as long as you don't accidentally return a `String` there instead of a `SomeLibrary::UselessModule::Ruby19Hack::XMLNode` you never knew existed. This has *got* to be simple to express for a Ruby type system. I'm considering `?` but worry it will be confused with the Java covariance/contravariance `? super Y`/`? extends Z` notations. Maybe '?!', with '?' meaning 'no idea,' and '?!' meaning 'no idea, but keep it strict.' I like the idea of using '!' as a way to easily add strictness to certain rules, since I hope for the defaults for most annotations to be "the most common" scenarios. Contravariance, for example, is typical in generic type parameters for argument parameters. I intend to ask the developer to add extra characters to their annotation to request invariance or covariance in that position. The same holds true for covariance in return values, invariance in container type parameters (which I expect to be more common but still not as common as covariance).
75
+
76
+ ## Duh: Duck Typing
77
+
78
+ Responds-to. Has to be dead simple and *natural*. I like the idea of using hashes:
79
+
80
+ # @return-type #read
81
+ def get_stream
82
+ MagicIOFairy.visit
83
+ end
84
+
85
+ # @return-type #write(#to_s)
86
+ def get\_universal\_writer
87
+ stream = MagicIOFairy.visit
88
+ def stream.write(y)
89
+ super(y.to_s)
90
+ end
91
+ stream
92
+ end
93
+
94
+ but I'm not sure yet.
95
+
96
+ ## Motherfuckin' Tuples.
97
+
98
+ The *most common API is Ruby* is Rack's #call syntax, and it must return a tuple!
99
+
100
+ DRuby has it so I better have it. I like their syntax:
101
+
102
+ # @return-type (Fixnum, String => String, String)
103
+ def call
104
+ [200, {'content-type' => 'text/plain'}, 'Hello, World!']
105
+ end
106
+
107
+ For some reason, for them Tuples are subtypes of "Top". That's.... foolish.
108
+ `Tuple<T1, T2, ..., Tn>` is clearly a subtype of `Array<BasicObject>` if not
109
+ `Array<SomeMoreSpecificCommonSuperclass>`. It's actually a dependent type, which DRuby
110
+ doesn't do in a general way. I intend to address dependent types in at least a limited
111
+ fashion. I will definitely allow for dynamic semantic checking of dependent types, but
112
+ the really interesting part is of course the static analysis. I'm not writing a proof
113
+ checker like Coq's, thank you very much.
114
+
115
+ Not much else to say. I think it may introduce ambiguity with my ideas for function
116
+ type annotations, though. I was going to have a function that had no interesting return
117
+ type be able to be left out. However that means that an n-argument function type with no
118
+ interesting return type is *the same type* as a function from that 1 argument to... nothing,
119
+ since it's now of type `(ArgType) -> NothingInteresting`. If you drop the NothingInteresting,
120
+ your syntax is `(ArgType) -> ` or `(ArgType)`. To me, the first is clearly a function to void,
121
+ but it means the programmer has to type out something for something that doesn't matter. The
122
+ latter is ambiguous with the 1-argument tuple type `(ArgType)`. Can't have ambiguity. Not for
123
+ a mini annotation language i want people to use foreals. However,
124
+ there is one very good thing: no object in Ruby itself is "callable" - you can't do:
125
+
126
+ x = FooBar.new
127
+ x(5)
128
+
129
+ and expect that to call a function. That's because it will look to call a method. So we actually
130
+ don't have any objects with names that are of function type. So whenever you annotate something callable,
131
+ you're using the #call idiom, and so 'function types' get swept away to structural typing! I think
132
+ I may provide a special syntax as a shortcut for #call, as it's a common thing to structurally type
133
+ (even `Rack` picked it – it's a great name for a `Runnable` (from Java) or Functor method).
134
+
135
+ # list: Array<String>
136
+ # proc: (String)
137
+ def each_proc(list, proc)
138
+ list.each {|x| proc.call(x)}
139
+ end
140
+
141
+ The one time you might want to annotate a "function type" is when you're describing a method in
142
+ what I call *compact* form: it's just a type declaration all at once, no separate lines for
143
+ each argument or return type. I refuse to require you to type the name of a method in the docs
144
+ just above the method, so it's just a function type:
145
+
146
+ # (Fixnum, Fixnum) -> Fixnum= | Bignum=
147
+ def add(a, b)
148
+ a + b
149
+ end
150
+
151
+ A method with 1 argument and an uninteresting return type is thus annotated as such:
152
+
153
+ # (#to_s) ->
154
+ def write(x)
155
+ @stream.write(x)
156
+ end
157
+
158
+ or
159
+
160
+ # (#to_s)
161
+ def write(x)
162
+ @stream.write(x)
163
+ end
164
+
165
+ Which is the same as a 1-argument tuple. However: I *know* in this case that the syntax is being used
166
+ to describe a function, never a 1-argument tuple. So there is no ambiguity here. All other objects of
167
+ function type would need to use the name of a method, so I'm in the clear for ambiguity. However, I
168
+ will remind users that this is there but probably won't bite them.
169
+
170
+ ## Customizable annotation syntax?
171
+
172
+ Switch between Haskell-like and C-like? Specify a function as `Fixnum doubler(Fixnum)` instead of go-like syntax?
173
+
174
+ ## Method Generation
175
+
176
+ Most importantly added to method_missing as an annotation, but could possibly be moved to other places: listing generated methods. Now, you might want to just list a bunch of methods that will get created at load time:
177
+
178
+ # generates: doubler(#to_i) Fixnum
179
+ # generates: tripler(#to_i) Fixnum
180
+ # generates: quadrupler(#to_i) Float
181
+ [[2, 'doubler'],[3, 'tripler'],[4.0,'quadupler']].each do |num, name|
182
+ define_method name do |y|
183
+ y.to_i * num
184
+ end
185
+ end
186
+
187
+ Which would generate type notes for 3 methods it then assumes exist with those annotations. Of course you can specify multiple overloads for these just by adding more lines:
188
+
189
+ # generates: doubler(Fixnum) Fixnum
190
+ # overflow lawlz
191
+ # generates: doubler(Fixnum) Bignum
192
+
193
+ ## Varargs
194
+
195
+ DRuby screwed the pooch on this one. First of all, you can tell just by looking at the damn method declaration that the argument is a vararg list. It already has a damn star on it. Also, they talk in their manual about how it makes "parameter list types as first-class types". I'm not entirely clear about that, because a parameter list in Ruby is just an `Array`. Anyway, I think it's important for people to be able to have
196
+ a way to note in the type declaration that something is a vararg. Or they could do that with `Array<Type>`. Or they might want me to infer it from the big effing star in their argument list.
197
+
198
+ I think I'm going to allow `*` to denote a vararg, and require its use if you want to enter a type annotation for something. No just writing "String" and letting me figure out that of course it's `Array<String>`. (Unless, of course, you use a certain flag, since I'll be happy to let you shoot yourself in the foot for it. Oh, and it won't work if it's an Array of Arrays, because there'd be ambiguity in the grammar there.)
199
+
200
+ ## Arbitrary annotations
201
+
202
+ Things like "could_raise?" (for functions) or "pure" (for functions) are going to be accessible from the type system. Since those are just going to be instances of a more general labeling system the user can extend themselves, that means the user can define their own tags. For example, a user wants to eventually deprecate an API. They want to do it quick and dirty, so they implement the "[v1]" tag. Take your V1API module, slap the entire module with [v1]. Bam. Every class in that module is now deprecated. Then later, when you think you're done with the migration, require [v1=false] on your arguments to a method. If it fails type-checking, then that means I can prove a non-deprecated object will make its way to to that method, and you must not have fully removed all uses of the deprecated code. A smarter way would be of course to deprecate 1 method at a time, by adding the @deprecated or [v1] tag around. I could integrate this with YARD's existing tag system, though I don't want to get mucked up in Documentation-related code.
203
+
204
+ ## Overloads
205
+
206
+ Overloads have to be done right, because they're pretty common. Especially in the standard library, and I'm going to have to type these damn annotations.
207
+
208
+ For one, you could just write each new possibility as separate lines, as DRuby does.
209
+
210
+ # (Fixnum) -> Fixnum | nil
211
+ # (Fixnum, Fixnum) -> String | nil
212
+ def slice(*args)
213
+ end
214
+
215
+ Of course slice has all kinds of other overloads, but this is simple enough. Notice that | binds tighter than the method arrow. That means it also works just fine for the "elided arrow" style that Go uses:
216
+
217
+ # (Fixnum, Fixnum) String | nil
218
+ # |---------------||-----|-|---|
219
+ # |---------------||-----------|
220
+ # |----------------------------|
221
+
222
+ Yay for a bootleg ascii concrete parse tree.
223
+
224
+ It's fine with me, to be honest.
225
+
226
+ ## Blocks?
227
+
228
+ How to annotate blocks? Not sure yet. Explicit blocks as arguments need to be annotated as well, though
229
+ they're another case of simple structural typing on #call. Oh, and I want to be able to annotate
230
+ how many *times* the block gets called. Possibly as a function of the arguments, so this could be
231
+ profiled at runtime. See contracts later.
232
+
233
+ But yeah, specifying that either the current function yields and what it yields is important. What
234
+ the block itself returns is also important. I saw DRuby trying to specify the type for Proc#initialize
235
+ and it made my brain hurt, even though Proc#initialize is just a no-arg function, that takes a block
236
+ with args and a return value, and returns #call(ArgTuple -> RetType). But the declaration was horrid:
237
+
238
+ ##% initialize: () {(^args) -> ret} -> Proc<^args, ret>
239
+ def initialize(); end
240
+
241
+ You couldn't pay me to type that out. Do I know better? Not sure yet, but for one, I'd prefer this:
242
+
243
+ # {*args -> ret} -> #call(*args) -> ret
244
+ def initialize; end
245
+
246
+ But even that feels like pushing it to me.
247
+
248
+ # {*args ret} #call(*args) ret
249
+
250
+ Is what that example would be with the unnecessary arrows. I like that the braces so "this stuff is
251
+ block stuff!" The more symbols I use, the more arcane it becomes, unfortunately. I bet people would
252
+ prefer more english words, but I should look into that first. DRuby uses `or` for Union types, after all.
253
+
254
+ ## Contracts
255
+
256
+ Used as a preprocessor, Laser could inject contracts into specified locations in methods. These could
257
+ be used for both assertions (invariants) and to profile code. So the user should be able to have simple
258
+ syntax for common contracts, but also have the fully power of arbitrary Ruby to put in there. That way,
259
+ you run in dev mode with the contracts on, and when run in production *all those assertions disappear*.
260
+ But the nice thing is, they're still there *as documentation*!
261
+
262
+ I haven't fleshed this out enough and it's going to be the last part of my work. Loren Segal is working
263
+ in this area as well.
264
+
265
+ ## Dependent Types
266
+
267
+ How much dependent typing can I support? Literals lend themselves to a few (array length forming a tuple),
268
+ but beyond those? How about: the keys of this hash come from this set. That's a good one. Rails probably
269
+ wastes tons of time manually checking those. Of course, they'd never *remove* them to protect users... but they'd know during
270
+ development that their own code isn't using them wrong without running the code to find out!
271
+ Oh, and whether a string is frozen or not, though this could be done with a generic type over TrueClass and
272
+ FalseClass. Technically, no need to invoke dependent types.
273
+
274
+ ## Detecting Data Dependencies?
275
+
276
+ Here's an interesting note about this: I may not be able to do dependent type checking without a hugely
277
+ complicated proof checker, but by allowing the annotation of dependent types, I can find *data dependencies*
278
+ whenever code converts a non-dependent version of the type (ie: Hash<Symbol => Object>) to the dependent one,
279
+ (i.e. Hash<SymbolInSomeSet => Object>), without an annotation, we are observing the moment when the code makes
280
+ the assumption that the the object is of the correct dependent type.
281
+
282
+ For example, if you read in a configuration YAML file and assign keys to values in a Hash in a method #read_file, you could have this
283
+ dependent type annotation saying that #read_file returns an `Hash<SymbolInSomeSet => Object>` object, then
284
+ when the code executes `hash[key.to_sym] = value`, that `key.to_sym` is of type `Symbol`, not `SymbolInSomeSet`.
285
+ Since `Hash<SomeSymbolInSomeSet => Object>`'s `[]=` method is of type `(SomeSymbolInSomeSet) -> Object`, we
286
+ must coerce SomeSymbolInSomeSet into a Symbol. This is the data dependency, and our general-purpose static
287
+ analysis tool can detect them and require a disclaimer saying "hey, i know this is a data dependency here."
288
+
289
+ ## Mutability
290
+
291
+ When annotating a type, you should mark if it will be mutated. That way you don't have to type when something
292
+ is `const` or immutable. As it should be.
293
+
294
+ I like the idea of using `!` to indicate mutation, so perhaps just adding a ! at the end of a type adds [mutable = true] as a custom annotation (described above).
295
+
296
+ ## Refinements
297
+
298
+ It'd be huge to support these out the gate. It should be inferable extremely easily.
@@ -0,0 +1,6 @@
1
+ Just noticed that the "Strict Unknowns" I described yesterday is already in-place
2
+ with only 1 specific constraint (super/sub-typing from a given class). I kind of
3
+ like my addition of "no idea but ensure consistency across calls" idea, and allowing
4
+ generic constraints is awesome.
5
+
6
+ Also, Scala uses `_`to mean "unknown", so I'm stealing it.
@@ -0,0 +1,65 @@
1
+ require 'test/unit'
2
+
3
+ require 'laser/third_party/rgl/traversal'
4
+ require 'laser/third_party/rgl/connected_components'
5
+ require 'laser/third_party/rgl/adjacency'
6
+ require_relative 'test_helper'
7
+
8
+ include RGL
9
+
10
+ def graph_from_string(s)
11
+ g = DirectedAdjacencyGraph.new(Array)
12
+ s.split(/\n/).collect{|x| x.split(/->/)}.each do |a|
13
+ from = a[0].strip
14
+ a[1].split.each do |to|
15
+ g.add_edge from,to
16
+ end
17
+ end
18
+ g
19
+ end
20
+
21
+ class TestComponents < Test::Unit::TestCase
22
+
23
+ def setup
24
+ @dg = DirectedAdjacencyGraph.new(Array)
25
+ edges = [[1,2],[2,3],[2,4],[4,5],[1,6],[6,4]]
26
+ edges.each do |(src,target)|
27
+ @dg.add_edge(src, target)
28
+ end
29
+ @bfs = @dg.bfs_iterator(1)
30
+ @dfs = @dg.dfs_iterator(1)
31
+
32
+ @ug = AdjacencyGraph.new(Array)
33
+ @ug.add_edges(*edges)
34
+
35
+ @dg2 = graph_from_string(
36
+ "a -> b f h
37
+ b -> c a
38
+ c -> d b
39
+ d -> e
40
+ e -> d
41
+ f -> g
42
+ g -> f d
43
+ h -> i
44
+ i -> h j e c")
45
+ end
46
+
47
+ def test_connected_components
48
+ ccs = []
49
+ @ug.each_connected_component { |c| ccs << c }
50
+ assert_equal(1,ccs.size)
51
+
52
+ ccs = []
53
+ @ug.add_edge 10,11
54
+ @ug.add_edge 33,44
55
+ @ug.each_connected_component { |c| ccs << c.sort }
56
+ assert_equal([[10, 11], [1, 2, 3, 4, 5, 6], [33,44]].sort,ccs.sort)
57
+ end
58
+
59
+ def test_strong_components
60
+ vis = @dg2.strongly_connected_components
61
+
62
+ assert_equal(4,vis.num_comp)
63
+ assert_equal([["a", 3], ["b", 3], ["c", 3], ["d", 0], ["e", 0], ["f", 1], ["g", 1], ["h", 3], ["i", 3], ["j", 2]],vis.comp_map.to_a)
64
+ end
65
+ end
@@ -0,0 +1,61 @@
1
+ $LOAD_PATH << "../lib"
2
+ require 'test/unit'
3
+ require 'laser/third_party/rgl/adjacency'
4
+ require_relative 'test_helper'
5
+
6
+ include RGL
7
+
8
+ class TestCycles < Test::Unit::TestCase
9
+
10
+ def setup
11
+ @dg = DirectedAdjacencyGraph.new(Array)
12
+ edges = [[1,2],[2,2],[2,3],[3,4],[4,5],[5,1],[6,4],[6,6],[1,4],[7,7],[7,7]]
13
+ edges.each do |(src,target)|
14
+ @dg.add_edge(src, target)
15
+ end
16
+
17
+ @ug = AdjacencyGraph.new(Array)
18
+ @ug.add_edges(*edges)
19
+ end
20
+
21
+ # Helper for testing for different permutations of a cycle
22
+ def contains_cycle?(cycles,cycle)
23
+ cycle.size.times do |i|
24
+ return true if cycles.include?(cycle)
25
+ cycle = cycle[1..-1] + [cycle[0]]
26
+ end
27
+ end
28
+
29
+ def test_cycles
30
+ d_cycles = @dg.cycles
31
+ assert_equal 6, d_cycles.size
32
+ assert d_cycles.include?([6])
33
+ assert d_cycles.include?([7])
34
+ assert d_cycles.include?([2])
35
+ assert contains_cycle?(d_cycles, [1,4,5])
36
+ assert contains_cycle?(d_cycles, [1,2,3,4,5])
37
+
38
+ assert_equal 5, DirectedAdjacencyGraph.new(Set, @dg).cycles.size
39
+
40
+ u_cycles = AdjacencyGraph.new(Set, @dg).cycles.sort
41
+
42
+ assert u_cycles.include?([2])
43
+ assert u_cycles.include?([6])
44
+ assert u_cycles.include?([7])
45
+ assert contains_cycle?(u_cycles, [1,2,3,4,5])
46
+ assert contains_cycle?(u_cycles, [1,5,4,3,2])
47
+ assert contains_cycle?(u_cycles, [1,4,3,2])
48
+ assert contains_cycle?(u_cycles, [1,4,5])
49
+ assert contains_cycle?(u_cycles, [1,5,4])
50
+ assert contains_cycle?(u_cycles, [1,5])
51
+ assert contains_cycle?(u_cycles, [1,2])
52
+ assert contains_cycle?(u_cycles, [1,2,3,4])
53
+ assert contains_cycle?(u_cycles, [2,3])
54
+ assert contains_cycle?(u_cycles, [1,4])
55
+ assert contains_cycle?(u_cycles, [3,4])
56
+ assert contains_cycle?(u_cycles, [4,5])
57
+ assert contains_cycle?(u_cycles, [4,6])
58
+ assert_equal 16, u_cycles.size
59
+ end
60
+
61
+ end
@@ -0,0 +1,125 @@
1
+ require 'test/unit'
2
+ require 'laser/third_party/rgl/adjacency'
3
+
4
+ include RGL
5
+ include RGL::Edge
6
+
7
+ class TestDirectedGraph < Test::Unit::TestCase
8
+ def setup
9
+ @dg = DirectedAdjacencyGraph.new
10
+ [[1,2],[2,3],[3,2],[2,4]].each do |(src,target)|
11
+ @dg.add_edge(src, target)
12
+ end
13
+ end
14
+
15
+ def test_empty_graph
16
+ dg = DirectedAdjacencyGraph.new
17
+ assert dg.empty?
18
+ assert dg.directed?
19
+ assert(!dg.has_edge?(2,1))
20
+ assert(!dg.has_vertex?(3))
21
+ # Non existend vertex result in a Name Error because each_key is
22
+ # called for nil
23
+ assert_raises(NoVertexError) {dg.out_degree(3)}
24
+ assert_equal([],dg.vertices)
25
+ assert_equal(0,dg.size)
26
+ assert_equal(0,dg.num_vertices)
27
+ assert_equal(0,dg.num_edges)
28
+ assert_equal(DirectedEdge,dg.edge_class)
29
+ assert([].eql?(dg.edges))
30
+ end
31
+
32
+ def test_add
33
+ dg = DirectedAdjacencyGraph.new
34
+ dg.add_edge(1,2)
35
+ assert(!dg.empty?)
36
+ assert(dg.has_edge?(1,2))
37
+ assert(!dg.has_edge?(2,1))
38
+ assert(dg.has_vertex?(1) && dg.has_vertex?(2))
39
+ assert(!dg.has_vertex?(3))
40
+
41
+ assert_equal([1,2],dg.vertices.sort)
42
+ assert([DirectedEdge.new(1,2)].eql?(dg.edges))
43
+ assert_equal("(1-2)",dg.edges.join)
44
+
45
+ assert_equal([2],dg.adjacent_vertices(1))
46
+ assert_equal([],dg.adjacent_vertices(2))
47
+
48
+ assert_equal(1,dg.out_degree(1))
49
+ assert_equal(0,dg.out_degree(2))
50
+ end
51
+
52
+ def test_edges
53
+ assert_equal(4, @dg.edges.count)
54
+ assert_equal([1,2,2,3], @dg.edges.map {|l| l.source}.sort)
55
+ assert_equal([2,2,3,4], @dg.edges.map {|l| l.target}.sort)
56
+ assert_equal("(1-2)(2-3)(2-4)(3-2)", @dg.edges.map {|l| l.to_s}.sort.join)
57
+ # assert_equal([0,1,2,3], @dg.edges.map {|l| l.info}.sort)
58
+ end
59
+
60
+ def test_vertices
61
+ assert_equal([1,2,3,4], @dg.vertices.sort)
62
+ end
63
+
64
+ def test_edges_from_to?
65
+ assert @dg.has_edge?(1,2)
66
+ assert @dg.has_edge?(2,3)
67
+ assert @dg.has_edge?(3,2)
68
+ assert @dg.has_edge?(2,4)
69
+ assert !@dg.has_edge?(2,1)
70
+ assert !@dg.has_edge?(3,1)
71
+ assert !@dg.has_edge?(4,1)
72
+ assert !@dg.has_edge?(4,2)
73
+ end
74
+
75
+ def test_remove_edges
76
+ @dg.remove_edge 1,2
77
+ assert !@dg.has_edge?(1,2)
78
+ @dg.remove_edge 1,2
79
+ assert !@dg.has_edge?(1,2)
80
+ @dg.remove_vertex 3
81
+ assert !@dg.has_vertex?(3)
82
+ assert !@dg.has_edge?(2,3)
83
+ assert_equal('(2-4)',@dg.edges.join)
84
+ end
85
+
86
+ def test_add_vertices
87
+ dg = DirectedAdjacencyGraph.new
88
+ dg.add_vertices 1,3,2,4
89
+ assert_equal dg.vertices.sort, [1,2,3,4]
90
+
91
+ dg.remove_vertices 1,3
92
+ assert_equal dg.vertices.sort, [2,4]
93
+ end
94
+
95
+ def test_creating_from_array
96
+ dg = DirectedAdjacencyGraph[1, 2, 3, 4]
97
+ assert_equal([1,2,3,4], dg.vertices.sort)
98
+ assert_equal('(1-2)(3-4)', dg.edges.join)
99
+ end
100
+
101
+ def test_reverse
102
+ reverted = @dg.reverse
103
+ @dg.each_edge do |u,v|
104
+ assert(reverted.has_edge?(v,u))
105
+ end
106
+ end
107
+
108
+ def test_reverse
109
+ # Add isolated vertex
110
+ @dg.add_vertex(42)
111
+ reverted = @dg.reverse
112
+
113
+ @dg.each_edge do |u,v|
114
+ assert(reverted.has_edge?(v,u))
115
+ end
116
+
117
+ assert(reverted.has_vertex?(42),
118
+ 'Reverted graph should contain isolated Vertex 42')
119
+ end
120
+
121
+ def test_to_undirected
122
+ undirected = @dg.to_undirected
123
+ assert_equal '(1=2)(2=3)(2=4)', undirected.edges.sort.join
124
+ end
125
+ end