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,35 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe MisalignedUnindentationWarning do
4
+ describe 'when fixing' do
5
+ it 'is a line-based warning' do
6
+ MisalignedUnindentationWarning.new('(stdin)', 'hello', 80).should be_a(LineWarning)
7
+ end
8
+
9
+ it 'matches nothing' do
10
+ MisalignedUnindentationWarning.should_not warn(' a + b', 2)
11
+ end
12
+
13
+ it 'fixes by removing more spaces than expected' do
14
+ MisalignedUnindentationWarning.should correct_to(' a + b', ' a + b', 2)
15
+ end
16
+
17
+ it 'fixes by adding a second space' do
18
+ MisalignedUnindentationWarning.should correct_to(' a + b', ' a + b', 2)
19
+ end
20
+
21
+ it 'fixes by adding indentation' do
22
+ MisalignedUnindentationWarning.should correct_to('a + b', ' a + b', 4)
23
+ end
24
+
25
+ it 'describes the incorrect indentation values' do
26
+ warning = MisalignedUnindentationWarning.new('(stdin)', ' a + b', 2)
27
+ other_warning = MisalignedUnindentationWarning.new('(stdin)', ' a + b', 2)
28
+ warning_3 = MisalignedUnindentationWarning.new('(stdin)', 'a + b', 4)
29
+ warning.desc.should =~ /Expected 2/
30
+ warning.desc.should =~ /found 3/
31
+ other_warning.desc.should =~ /Expected 2/
32
+ other_warning.desc.should =~ /found 1/
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,104 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe OperatorSpacing do
4
+ it 'is a line-based warning' do
5
+ OperatorSpacing.new('(stdin)', 'hello').should be_a(LineWarning)
6
+ end
7
+
8
+ it "doesn't match block declarations" do
9
+ OperatorSpacing.should_not warn('[1, 2].each { |x| p x }')
10
+ OperatorSpacing.should_not warn('[1, 2].each {| y | p x }')
11
+ OperatorSpacing.should_not warn("[1, 2].each do |x|\n p x\nend")
12
+ OperatorSpacing.should_not warn("[1, 2].each do|x|\n p x\nend")
13
+ end
14
+
15
+ it "doesn't match in a comment" do
16
+ OperatorSpacing.should_not warn('hello # a+b')
17
+ end
18
+
19
+ it "doesn't match a <<- heredoc" do
20
+ OperatorSpacing.should_not warn('@original = <<-EOF')
21
+ end
22
+
23
+ it "doesn't match a << heredoc" do
24
+ OperatorSpacing.should_not warn('@original = <<EOF')
25
+ end
26
+
27
+ it "doesn't match adjacent negative numbers" do
28
+ OperatorSpacing.should_not warn(' exit(-1)')
29
+ end
30
+
31
+ it "doesn't match *args in block parameters" do
32
+ OperatorSpacing.should_not warn('list.each do |*args|')
33
+ OperatorSpacing.should_not warn('list.each { |*args| }')
34
+ end
35
+
36
+ it "doesn't match splat arguments" do
37
+ OperatorSpacing.should_not warn('x.call(*args)')
38
+ OperatorSpacing.should_not warn('x.call(a, *args)')
39
+ OperatorSpacing.should_not warn('x.call(*args, b)')
40
+ OperatorSpacing.should_not warn('x.call(a, *args, b)')
41
+ end
42
+
43
+ it "does match multiplication in an argument list" do
44
+ OperatorSpacing.should warn('x.call(a *b)')
45
+ OperatorSpacing.should warn('x.call(x, a *b)')
46
+ OperatorSpacing.should warn('x.call(a *b, z)')
47
+ end
48
+
49
+ it "doesn't match block arguments" do
50
+ OperatorSpacing.should_not warn('x.call(&b)')
51
+ OperatorSpacing.should_not warn('x.call(a, &b)')
52
+ OperatorSpacing.should_not warn('x.call(&b, b)')
53
+ OperatorSpacing.should_not warn('x.call(a, &b, b)')
54
+ OperatorSpacing.should_not warn('@peek = wrapped_stream.move_forward_until(&@filter) or return true')
55
+ OperatorSpacing.should_not warn('wrapped_stream.move_forward_until(&@filter)')
56
+ OperatorSpacing.should_not warn('wrapped_stream.move_backward_until(&@filter) or self')
57
+ end
58
+
59
+ it "doesn't match the [*item] idiom" do
60
+ OperatorSpacing.should_not warn('[*args]')
61
+ end
62
+
63
+ it 'has a reasonable description' do
64
+ OperatorSpacing.new('(stdin)', 'a+ b').desc.should =~ /spacing/
65
+ end
66
+
67
+ OperatorSpacing::OPERATORS.each do |operator|
68
+ describe "with #{operator}" do
69
+ it "matches when there is no space on the left side" do
70
+ OperatorSpacing.should warn("a#{operator} b")
71
+ end
72
+
73
+ it "matches when there is no space on the right side" do
74
+ OperatorSpacing.should warn("a #{operator}b")
75
+ end unless operator == '/' # This confuses the shit out of the lexer
76
+
77
+ it "matches when there is no space on both sides" do
78
+ OperatorSpacing.should warn("a#{operator}b")
79
+ end
80
+
81
+ it "doesn't match when there is exactly one space on both sides" do
82
+ OperatorSpacing.should_not warn("a #{operator} b")
83
+ end
84
+
85
+ describe 'when fixing' do
86
+ it 'changes nothing when there is one space on both sides' do
87
+ OperatorSpacing.should correct_to("a #{operator} b", "a #{operator} b")
88
+ end
89
+
90
+ it 'fixes by inserting an extra space on the left' do
91
+ OperatorSpacing.should correct_to("a#{operator} b", "a #{operator} b")
92
+ end
93
+
94
+ it 'fixes by inserting an extra space on the right' do
95
+ OperatorSpacing.should correct_to("a #{operator}b", "a #{operator} b")
96
+ end unless operator == '/' # This confuses the shit out of the lexer
97
+
98
+ it 'fixes by inserting an extra space on both sides' do
99
+ OperatorSpacing.should correct_to("a#{operator}b", "a #{operator} b")
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,57 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe ParensOnDeclarationWarning do
4
+ it 'is a file-based warning' do
5
+ ParensOnDeclarationWarning.new('(stdin)', 'hello').should be_a(FileWarning)
6
+ end
7
+
8
+ context 'with a normal method definition' do
9
+ it 'matches when a method has arguments with no parens around them' do
10
+ ParensOnDeclarationWarning.should warn('def abc arg; end')
11
+ end
12
+
13
+ it 'matches when a method with no arguments is declared with parentheses' do
14
+ ParensOnDeclarationWarning.should warn('def abc(); end')
15
+ end
16
+
17
+ it 'does not match when arguments are surrounded by parentheses' do
18
+ ParensOnDeclarationWarning.should_not warn('def abc(arg); end')
19
+ end
20
+
21
+ it 'does not match when there are no arguments' do
22
+ ParensOnDeclarationWarning.should_not warn('def abc; end')
23
+ end
24
+
25
+ describe '#desc' do
26
+ it 'includes the name of the offending method' do
27
+ matches = ParensOnDeclarationWarning.new('(stdin)', 'def silly_monkey arg1, *rest; end').match?
28
+ matches[0].desc.should =~ /silly_monkey/
29
+ end
30
+ end
31
+ end
32
+
33
+ context 'with a singleton definition' do
34
+ it 'matches when a method has arguments with no parens around them' do
35
+ ParensOnDeclarationWarning.should warn('def self.abc arg; end')
36
+ end
37
+
38
+ it 'matches when a method with no arguments is declared with parentheses' do
39
+ ParensOnDeclarationWarning.should warn('def self.abc(); end')
40
+ end
41
+
42
+ it 'does not match when arguments are surrounded by parentheses' do
43
+ ParensOnDeclarationWarning.should_not warn('def self.abc(arg); end')
44
+ end
45
+
46
+ it 'does not match when there are no arguments' do
47
+ ParensOnDeclarationWarning.should_not warn('def self.abc; end')
48
+ end
49
+
50
+ describe '#desc' do
51
+ it 'includes the name of the offending method' do
52
+ matches = ParensOnDeclarationWarning.new('(stdin)', 'def self.silly_monkey arg1, *rest; end').match?
53
+ matches[0].desc.should =~ /silly_monkey/
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,105 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe RescueExceptionWarning do
4
+ it 'is a file-based warning' do
5
+ RescueExceptionWarning.new('(stdin)', 'hello').should be_a(FileWarning)
6
+ end
7
+
8
+ it 'matches against a rescue of Exception as the only type' do
9
+ RescueExceptionWarning.should warn('begin; puts x; rescue Exception; end')
10
+ end
11
+
12
+ it 'does not match when a rescue of StandardError is used' do
13
+ RescueExceptionWarning.should_not warn('begin; puts x; rescue StandardError; end')
14
+ end
15
+
16
+ it 'matches against a rescue of Exception with an additional identifier' do
17
+ RescueExceptionWarning.should warn('begin; puts x; rescue Exception => e; end')
18
+ end
19
+
20
+ it 'does not match when a rescue of StandardError is used with an additional identifier' do
21
+ RescueExceptionWarning.should_not warn('begin; puts x; rescue StandardError => e; end')
22
+ end
23
+
24
+ it 'matches against a rescue of Exception that is specified second' do
25
+ RescueExceptionWarning.should warn('begin; puts x; rescue StandardError, Exception; end')
26
+ end
27
+
28
+ it 'does not match when a rescue of StandardError is specified second' do
29
+ RescueExceptionWarning.should_not warn('begin; puts x; rescue StandardError, StandardError; end')
30
+ end
31
+
32
+ it 'matches against a rescue of Exception that is specified second w/ addl identifier' do
33
+ RescueExceptionWarning.should warn('begin; puts x; rescue StandardError, Exception => err; end')
34
+ end
35
+
36
+ it 'does not match when a rescue of StandardError is specified second w/ addl identifier' do
37
+ RescueExceptionWarning.should_not warn('begin; puts x; rescue StandardError, StandardError => err; end')
38
+ end
39
+
40
+ describe '#fix' do
41
+ it 'fixes a rescue of Exception as the only type' do
42
+ input = <<-EOF
43
+ begin
44
+ puts x
45
+ rescue Exception # bad
46
+ end
47
+ EOF
48
+ output = <<-EOF
49
+ begin
50
+ puts x
51
+ rescue StandardError # bad
52
+ end
53
+ EOF
54
+ RescueExceptionWarning.new('(stdin)', input).match?(input).first.fix.should == output
55
+ end
56
+
57
+ it 'fixes a rescue of Exception with an additional identifier' do
58
+ input = <<-EOF
59
+ begin
60
+ puts x
61
+ rescue Exception => e # bad
62
+ end
63
+ EOF
64
+ output = <<-EOF
65
+ begin
66
+ puts x
67
+ rescue StandardError => e # bad
68
+ end
69
+ EOF
70
+ RescueExceptionWarning.new('(stdin)', input).match?(input).first.fix.should == output
71
+ end
72
+
73
+ it 'fixes a rescue of Exception that is specified second' do
74
+ input = <<-EOF
75
+ begin
76
+ puts x
77
+ rescue StandardError, Exception # bad
78
+ end
79
+ EOF
80
+ output = <<-EOF
81
+ begin
82
+ puts x
83
+ rescue StandardError, StandardError # bad
84
+ end
85
+ EOF
86
+ RescueExceptionWarning.new('(stdin)', input).match?(input).first.fix.should == output
87
+ end
88
+
89
+ it 'fixes a rescue of Exception that is specified second w/ addl identifier' do
90
+ input = <<-EOF
91
+ begin
92
+ puts x
93
+ rescue StandardError, Exception => e # bad
94
+ end
95
+ EOF
96
+ output = <<-EOF
97
+ begin
98
+ puts x
99
+ rescue StandardError, StandardError => e # bad
100
+ end
101
+ EOF
102
+ RescueExceptionWarning.new('(stdin)', input).match?(input).first.fix.should == output
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,58 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe SemicolonWarning do
4
+ it 'is a line-based warning' do
5
+ SemicolonWarning.new('(stdin)', 'hello').should be_a(LineWarning)
6
+ end
7
+
8
+ it 'matches when a semicolon splits two expressions' do
9
+ SemicolonWarning.should warn('puts x; puts y')
10
+ end
11
+
12
+ it 'matches when a semicolon splits two expressions that have strings' do
13
+ SemicolonWarning.should warn('puts "x"; puts "y"')
14
+ end
15
+
16
+ it "doesn't match when a semicolon is in a string" do
17
+ SemicolonWarning.should_not warn('puts "x;y"')
18
+ end
19
+
20
+ it "doesn't match when a semicolon is in a single-quoted string" do
21
+ SemicolonWarning.should_not warn("puts 'x;y'")
22
+ end
23
+
24
+ it "doesn't match when a semicolon is used in an Exception definition" do
25
+ SemicolonWarning.should_not warn('class AError < BError; end"')
26
+ end
27
+
28
+ it 'has a lower severity when quotes are involved due to unsure-ness' do
29
+ SemicolonWarning.new('(stdin)', "hello' world' ; there").severity.should <
30
+ SemicolonWarning.new('(stdin)', 'hello world ; there').severity
31
+ end
32
+
33
+ it 'has a remotely descriptive description' do
34
+ SemicolonWarning.new('(stdin)', 'hello ; world').desc.should =~ /semicolon/
35
+ end
36
+
37
+ it "doesn't match when a semicolon is in a comment" do
38
+ SemicolonWarning.should_not warn("hello # indeed; i agree")
39
+ end
40
+
41
+ describe '#fix' do
42
+ it 'converts the simplest semicolon use to two lines' do
43
+ SemicolonWarning.should correct_to('a;b', "a\nb")
44
+ end
45
+
46
+ it 'converts the simplest triple semicolon use to two lines' do
47
+ SemicolonWarning.should correct_to('a;b;c', "a\nb\nc")
48
+ end
49
+
50
+ it 'maintains indentation on new lines' do
51
+ SemicolonWarning.should correct_to(' a;b', " a\n b")
52
+ end
53
+
54
+ it 'maintains indentation on all new lines' do
55
+ SemicolonWarning.should correct_to(' a;b;c', " a\n b\n c")
56
+ end
57
+ end
58
+ end
@@ -0,0 +1 @@
1
+ require_relative '../spec_helper'
@@ -0,0 +1,74 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe UselessDoubleQuotesWarning do
4
+ it 'is a file-based warning' do
5
+ UselessDoubleQuotesWarning.new('(stdin)', 'hello').should be_a(FileWarning)
6
+ end
7
+
8
+ it 'matches when a simple string is in double quotes unnecessarily' do
9
+ UselessDoubleQuotesWarning.should warn('simple "example, okay?"')
10
+ end
11
+
12
+ it 'matches when a simple string is in %Q{} unnecessarily' do
13
+ UselessDoubleQuotesWarning.should warn('simple %Q{example, okay?}')
14
+ end
15
+
16
+ it 'does not match when an escape sequence is used' do
17
+ UselessDoubleQuotesWarning.should_not warn('simple "example\n okay?"')
18
+ end
19
+
20
+ it 'does not match when an apostrophe is present' do
21
+ UselessDoubleQuotesWarning.should_not warn('simple "example\' okay?"')
22
+ end
23
+
24
+ it 'does not match when text interpolation is used' do
25
+ UselessDoubleQuotesWarning.should_not warn('simple "exaple\n #{h stuff} okay?"')
26
+ end
27
+
28
+ it 'does match when a useless double-quoted string is used inside text interpolation' do
29
+ UselessDoubleQuotesWarning.should warn('simple "example, #{h "guy"} okay?"')
30
+ end
31
+
32
+ it 'does not warn about single quotes that are nice and simple' do
33
+ UselessDoubleQuotesWarning.should_not warn("simple 'string is okay'")
34
+ end
35
+
36
+ it 'does not warn about %q syntax that are simple' do
37
+ UselessDoubleQuotesWarning.should_not warn("simple %q{string is okay}")
38
+ end
39
+
40
+ describe '#desc' do
41
+ it 'properly quotes the improperly quoted text' do
42
+ matches = UselessDoubleQuotesWarning.new('(stdin)', 'simple "example, #{h "guy"} okay?"').match?
43
+ matches[0].desc.should =~ /'guy'/
44
+ end
45
+
46
+ it 'properly quotes the improperly quoted text with %Q{}' do
47
+ matches = UselessDoubleQuotesWarning.new('(stdin)', 'simple "example, #{h %Q{guy}} okay?"').match?
48
+ matches[0].desc.should =~ /%q{guy}/
49
+ end
50
+ end
51
+
52
+ describe '#fix' do
53
+ it 'fixes a simple string using double quotes unnecessarily' do
54
+ checker = UselessDoubleQuotesWarning.new('(stdin)', 'simple "example, okay?"')
55
+ warnings = checker.match?
56
+ warnings.size.should == 1
57
+ warnings.first.fix('simple "example, okay?"').should == "simple 'example, okay?'"
58
+ end
59
+
60
+ it 'fixes a simple string using %Q{} unnecessarily' do
61
+ checker = UselessDoubleQuotesWarning.new('(stdin)', 'simple %Q{example, okay?}')
62
+ warnings = checker.match?
63
+ warnings.size.should == 1
64
+ warnings.first.fix('simple %Q{example, okay?}').should == "simple %q{example, okay?}"
65
+ end
66
+
67
+ it 'fixes a simple string inside a complex one' do
68
+ checker = UselessDoubleQuotesWarning.new('(stdin)', 'simple "example, #{h "guy"} okay?"')
69
+ warnings = checker.match?
70
+ warnings.size.should == 1
71
+ warnings.first.fix('simple "example, #{h "guy"} okay?"').should == 'simple "example, #{h \'guy\'} okay?"'
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,163 @@
1
+ Today, I've pushed significant work on Laser. It's still very rough around the edges, but I've got it doing the following new, cool, and somewhat-advanced analyses:
2
+
3
+ ## Using a semicolon to separate statements
4
+
5
+ If you'd like to warn against using a semicolon to separate statements on a single line, you can turn this warning on. However, due to personal preference, if you do this:
6
+
7
+ class MyError < StandardError; end
8
+
9
+ it won't complain. This, though:
10
+
11
+ puts x; puts y
12
+
13
+ will be an error. Laser is capable of fixing this error while maintaining indentation levels, up to arbitrary number of violating semicolons:
14
+
15
+ # some comment
16
+ p x; p y; p z; p 10
17
+
18
+ becomes
19
+
20
+ # some comment
21
+ p x
22
+ p y
23
+ p z
24
+ p 10
25
+
26
+ Cool, eh? I think I have this one nailed down to 100% accuracy, too.
27
+
28
+ ## Whitespace Tomfoolery
29
+
30
+ Two separate ones here, extra blank lines and trailing whitespace. Both of these are significant mainly because when you violate them, you hurt signal-to-noise in VCS diffs. Committing 2 rows deleted and added with just trailing whitespace differences is just a shame.
31
+
32
+ ### Extra Blank Lines
33
+
34
+ Ever leave blank lines at the end of your file? This warning tells you how many lines you left at the end, and fixes them if you wish.
35
+
36
+ ### Trailing Whitespace
37
+
38
+ Extra spaces and tabs at the end of a line fall in this category, and can be fixed without disturbing the source code.
39
+
40
+ ## Operator Spacing
41
+
42
+ This one is a bit dicy, but it tries to enforce spacing between operators. This gets tough because of lines with block declarations (where `|`s form the variable declaration area in a block, and do not act as a binary or operator), array splatting, block argument declarations, and so on. That's mainly a problem if you use regexes, which the current implementation does use. The parser will be employed shortly to remedy this situation.
43
+
44
+ ## Misaligned Indentation
45
+
46
+ This is another one that needs a bit of an overhaul, but it works pretty well so far. This warning checks how well you indent, namely, that you indent at consistent multiples, and that you unindent evenly. However, it doesn't yet take into account line continuation, where you should then indent relevant to the previous line (and not via the multiplication pattern). So it can detect and correct these mistakes:
47
+
48
+ if x
49
+ if y
50
+ if z
51
+ p x
52
+ end
53
+ end
54
+ end
55
+
56
+ becoming
57
+
58
+ if x
59
+ if y
60
+ if z
61
+ p x
62
+ end
63
+ end
64
+ end
65
+
66
+ Cool eh? It does make some mistakes though, and there are definite examples in the laser code itself that this will mess up on.
67
+
68
+ ## Line Length
69
+
70
+ Line Length is a fun one!
71
+
72
+ The line length warnings let you specify multiple levels of severity for different violations, such as a level 2 warning for being between 80-89 chars and a 4 for 90+. Detecting this is extremely simple. Also, it considers whitespace stripping when calculating a line's minimum possible length.
73
+
74
+ The really fun part is *fixing* it. Because Ruby code is sensitive to newlines, we can't just break it up into neat 80-char lines on the whitespace. So there's a few quick heuristics currently in play that I think are significant to brag about.
75
+
76
+ ### Comment Rearranging
77
+
78
+ If a line is over the limit, but it has a comment at the end of it, we know we can take the comment and put it on the line above. It really belongs there anyway if it's going off the edge – the line it's describing is long enough to go near the edge, so it's probably quite complex. Its comment should have its own line.
79
+
80
+ This heuristic however could create a *new* line that's over the limit, if the comment is comically long. So we also break the comment into correctly-sized lines, all indented to match the original line.
81
+
82
+ An example, if the max line length is 20:
83
+
84
+ puts x * y * z / a # this computes a significant equation involving math
85
+
86
+ you'll get back:
87
+
88
+ # this computes a
89
+ # significant
90
+ # equation involving
91
+ # math
92
+ # puts x * y * z / a
93
+
94
+ which still has no line length violations! It naturally smooths out at longer line lengths.
95
+
96
+ ### Guard rearranging
97
+
98
+ Here's one that bugs me. When I write a conditional Exception raise, I think of it this way:
99
+
100
+ raise FooBarError.new('Steve forgot to write the Foo bar library') unless steve.finished?
101
+
102
+ but that's usually way over the line length limit. In truth, I should check it in like this:
103
+
104
+ unless steve.finished?
105
+ raise FooBarError.new('Steve forgot to write the Foo bar library')
106
+ end
107
+
108
+ And if you use Laser now, you can leave code in the first form and it will transform to the second form! In fact, it works for multiple guards, too:
109
+
110
+ raise FooBarError.new('Steve forgot to write the Foo bar library') unless steve.finished?(schedule) if foo_bar.missing?(search_results) unless working?(test_data, &test_proc)
111
+
112
+ laser magically transforms into:
113
+
114
+ unless working?(test_data, &test_proc)
115
+ if foo_bar.missing?(search_results)
116
+ unless steve.finished?(schedule)
117
+ raise FooBarError.new('Steve forgot to write the Foo bar library')
118
+ end
119
+ end
120
+ end
121
+
122
+ Which is clean and better. It actually picks up on-the-line cases I missed on a somewhat regular basis!
123
+
124
+ That's all for line length shortening. I know there's a lot more to do with continued lines (ending a line with a `+` token before the line-length cutoff, for example, means you know you can break the line into a new one at that point, resulting in a smaller problem and 1 valid line. Repeating this with all the safe tokens should result in a *lot* of progress.
125
+
126
+ ## Inline comment spacing
127
+
128
+ My style guide (derived mainly from the Google style guide, with a few exceptions that everyone takes because it's a wee bit off) says that inline comments must have exactly 2 spaces between the last non-whitespace character and the hash mark beginning the comment. This is easily detected, enforced, and corrected. So Laser does!
129
+
130
+ ## Unnecessary Double Quotes
131
+
132
+ When you use double quotes, the parser has to go and check for string interpolation and escape sequences. This is also true when you use the `%Q{}` syntax. Thus it is slower to use double quotes or `%Q{}` when you don't need those features. Laser detects this and corrects double-quotes to single quotes (unless there is an escape sequence in the text or an apostrophe) and `%Q{}` to `%q{}`. It uses the raw AST, so it isn't error-prone like the regex-based passes.
133
+
134
+ ## `rescue Exception`
135
+
136
+ is bad! If you're rescuing Exception, you're rescuing a *lot* of things. You're covering up syntax errors. Just about the only thing you don't rescue is `SystemExit`. Almost always, you should be `rescue`ing `StandardError`. Laser currently can detect this based on the AST in all cases, but it cannot auto-correct them yet.
137
+
138
+ # Up Next: Immediate
139
+
140
+ Next, I'm going to start defining the API for constant-ness, with a tag on the AST that I'll make a pass to infer. I'll also be adding
141
+
142
+ default_attr_accessor :pure, false
143
+
144
+ to Method and Proc, so methods can be annotated as Pure. Thus, a method call on a constant object with constant arguments (if any) and a constant proc for a block (because it contains only pure calls...) is itself a constant expression. All these rules can be enumerated and inferred, and once the standard library batch of annotations is underway a lot of cool examples of success are going to come out of this. For example, [Rubinius](http://rubini.us) could use our constant-ness evaluator to (with a flag of course, not by default) allow constant assignment in methods to constant expressions:
145
+
146
+ def enable_global_settings
147
+ LOGGER = DEBUG_MODE ? StdoutLogger.new : nil
148
+ end
149
+
150
+ # Down The Line
151
+
152
+ Here's a quick brain dump of down-the-line ideas:
153
+
154
+ * Next large goal: Load in class and method defs in the main, simple cases, and hammer out an annotation system and a LALR(1) parser for it. Use racc to implement parser.
155
+ * I could discuss getting the annotations contributed to RubySpec. That's a bit boastful but hey, if they're accurate, they could be helpful.
156
+ * I'll be starting with the assumption that type annotations are available. That is because, in the spirit of [Gilad's pluggable types](http://bracha.org/pluggableTypesPosition.pdf) inference can be provided as tooling, but is not necessary to develop the rich type system you wish to describe.
157
+ * Rubinius could use an annotated method to improve code paths.
158
+ * I could dump the basic flow data I collect, including types of blocks and return types, variables, etc. to a database or YAML or something. I'll be getting a lot. That YAML could be integrated into an editor to provide hover-over type information. Smart autocomplete could be within reach, not that RubyMine is that bad.
159
+ * A few more syntax things should get done, and I need to overhaul how tokens come out of the lexer process, as right now I'm just handling them raw, which makes for horrible-to-maintain code.
160
+ * Coverage is near-100% in my eyes. The specs are just wonderful. There are a couple known bugs and those are in my sights.
161
+ * I tried integrating with Redcar to get an automatic "fix unnecessary double quotes" plugin going, but I ran into huge trouble. Laser needs Ruby 1.9.2, and Redcar uses JRuby, but for some reason when I ran redcar with `rvm use 1.9.2-head`, it blows up on startup. If I run redcar with `rvm use system`, it runs just as dandily as always, but now Laser won't run because it needs 1.9.2. Probably some loader magic to do to find a 1.9 ruby executable, potentially having to interact with `rvm` to infer it.
162
+
163
+ Stay tuned, as always, for more.