laser 0.7.0.pre1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +14 -0
  4. data/LICENSE +661 -0
  5. data/README.md +158 -0
  6. data/Rakefile +104 -0
  7. data/VERSION +1 -0
  8. data/bin/laser +7 -0
  9. data/design_docs/goals.md +57 -0
  10. data/design_docs/object_regex.md +426 -0
  11. data/design_docs/type_annotations.md +80 -0
  12. data/ext/laser/BasicBlock.cpp +572 -0
  13. data/ext/laser/BasicBlock.h +118 -0
  14. data/ext/laser/extconf.rb +3 -0
  15. data/features/laser.feature +25 -0
  16. data/features/step_definitions/laser_steps.rb +39 -0
  17. data/features/support/env.rb +14 -0
  18. data/features/support/testdata/1_input +1 -0
  19. data/features/support/testdata/1_output +1 -0
  20. data/features/support/testdata/2_input +4 -0
  21. data/features/support/testdata/2_output +4 -0
  22. data/features/support/testdata/3_input +8 -0
  23. data/features/support/testdata/3_output +11 -0
  24. data/features/support/testdata/4_input +5 -0
  25. data/features/support/testdata/4_output +5 -0
  26. data/features/support/testdata/5_input +13 -0
  27. data/laser.gemspec +382 -0
  28. data/lib/laser.rb +98 -0
  29. data/lib/laser/analysis/annotations.rb +95 -0
  30. data/lib/laser/analysis/annotations/annotation_config.yaml +3 -0
  31. data/lib/laser/analysis/annotations/comment_attachment_annotation.rb +66 -0
  32. data/lib/laser/analysis/annotations/node_pointers_annotation.rb +36 -0
  33. data/lib/laser/analysis/annotations/runtime_annotation.rb +55 -0
  34. data/lib/laser/analysis/argument_expansion.rb +132 -0
  35. data/lib/laser/analysis/arity.rb +34 -0
  36. data/lib/laser/analysis/bindings.rb +144 -0
  37. data/lib/laser/analysis/bootstrap/bootstrap.rb +298 -0
  38. data/lib/laser/analysis/bootstrap/laser_class.rb +106 -0
  39. data/lib/laser/analysis/bootstrap/laser_method.rb +255 -0
  40. data/lib/laser/analysis/bootstrap/laser_module.rb +403 -0
  41. data/lib/laser/analysis/bootstrap/laser_module_copy.rb +74 -0
  42. data/lib/laser/analysis/bootstrap/laser_object.rb +69 -0
  43. data/lib/laser/analysis/bootstrap/laser_proc.rb +150 -0
  44. data/lib/laser/analysis/bootstrap/laser_singleton_class.rb +44 -0
  45. data/lib/laser/analysis/comments.rb +35 -0
  46. data/lib/laser/analysis/control_flow.rb +28 -0
  47. data/lib/laser/analysis/control_flow/alias_analysis.rb +31 -0
  48. data/lib/laser/analysis/control_flow/basic_block.rb +105 -0
  49. data/lib/laser/analysis/control_flow/cfg_builder.rb +2505 -0
  50. data/lib/laser/analysis/control_flow/cfg_instruction.rb +190 -0
  51. data/lib/laser/analysis/control_flow/constant_propagation.rb +742 -0
  52. data/lib/laser/analysis/control_flow/control_flow_graph.rb +370 -0
  53. data/lib/laser/analysis/control_flow/lifetime_analysis.rb +91 -0
  54. data/lib/laser/analysis/control_flow/method_call_search.rb +26 -0
  55. data/lib/laser/analysis/control_flow/raise_properties.rb +25 -0
  56. data/lib/laser/analysis/control_flow/simulation.rb +385 -0
  57. data/lib/laser/analysis/control_flow/static_single_assignment.rb +185 -0
  58. data/lib/laser/analysis/control_flow/unreachability_analysis.rb +57 -0
  59. data/lib/laser/analysis/control_flow/unused_variables.rb +91 -0
  60. data/lib/laser/analysis/control_flow/yield_properties.rb +103 -0
  61. data/lib/laser/analysis/errors.rb +131 -0
  62. data/lib/laser/analysis/laser_utils.rb +18 -0
  63. data/lib/laser/analysis/lexical_analysis.rb +172 -0
  64. data/lib/laser/analysis/method_call.rb +68 -0
  65. data/lib/laser/analysis/protocol_registry.rb +30 -0
  66. data/lib/laser/analysis/scope.rb +118 -0
  67. data/lib/laser/analysis/sexp.rb +159 -0
  68. data/lib/laser/analysis/sexp_analysis.rb +40 -0
  69. data/lib/laser/analysis/sexp_extensions/constant_extraction.rb +115 -0
  70. data/lib/laser/analysis/sexp_extensions/source_location.rb +164 -0
  71. data/lib/laser/analysis/sexp_extensions/type_inference.rb +47 -0
  72. data/lib/laser/analysis/signature.rb +76 -0
  73. data/lib/laser/analysis/special_methods/send.rb +67 -0
  74. data/lib/laser/analysis/unused_methods.rb +21 -0
  75. data/lib/laser/analysis/visitor.rb +141 -0
  76. data/lib/laser/annotation_parser/annotations.treetop +126 -0
  77. data/lib/laser/annotation_parser/annotations_parser.rb +748 -0
  78. data/lib/laser/annotation_parser/class_annotations.treetop +82 -0
  79. data/lib/laser/annotation_parser/class_annotations_parser.rb +654 -0
  80. data/lib/laser/annotation_parser/overload.treetop +24 -0
  81. data/lib/laser/annotation_parser/overload_parser.rb +167 -0
  82. data/lib/laser/annotation_parser/parsers.rb +6 -0
  83. data/lib/laser/annotation_parser/structural.treetop +37 -0
  84. data/lib/laser/annotation_parser/structural_parser.rb +406 -0
  85. data/lib/laser/annotation_parser/useful_parsers.treetop +47 -0
  86. data/lib/laser/annotation_parser/useful_parsers_parser.rb +674 -0
  87. data/lib/laser/rake/task.rb +46 -0
  88. data/lib/laser/runner.rb +189 -0
  89. data/lib/laser/scanner.rb +169 -0
  90. data/lib/laser/standard_library/_thread.rb +110 -0
  91. data/lib/laser/standard_library/abbrev.rb +103 -0
  92. data/lib/laser/standard_library/array.rb +418 -0
  93. data/lib/laser/standard_library/base64.rb +91 -0
  94. data/lib/laser/standard_library/basic_object.rb +55 -0
  95. data/lib/laser/standard_library/benchmark.rb +556 -0
  96. data/lib/laser/standard_library/bignum.rb +185 -0
  97. data/lib/laser/standard_library/cgi.rb +275 -0
  98. data/lib/laser/standard_library/cgi/cookie.rb +147 -0
  99. data/lib/laser/standard_library/cgi/core.rb +791 -0
  100. data/lib/laser/standard_library/cgi/html.rb +1021 -0
  101. data/lib/laser/standard_library/cgi/session.rb +537 -0
  102. data/lib/laser/standard_library/cgi/session/pstore.rb +111 -0
  103. data/lib/laser/standard_library/cgi/util.rb +188 -0
  104. data/lib/laser/standard_library/class_definitions.rb +333 -0
  105. data/lib/laser/standard_library/comparable.rb +125 -0
  106. data/lib/laser/standard_library/complex.rb +162 -0
  107. data/lib/laser/standard_library/enumerable.rb +178 -0
  108. data/lib/laser/standard_library/exceptions.rb +135 -0
  109. data/lib/laser/standard_library/fixnum.rb +188 -0
  110. data/lib/laser/standard_library/float.rb +180 -0
  111. data/lib/laser/standard_library/hash.rb +237 -0
  112. data/lib/laser/standard_library/integer.rb +123 -0
  113. data/lib/laser/standard_library/laser_magic.rb +7 -0
  114. data/lib/laser/standard_library/nil_false_true.rb +113 -0
  115. data/lib/laser/standard_library/numbers.rb +192 -0
  116. data/lib/laser/standard_library/proc.rb +31 -0
  117. data/lib/laser/standard_library/set.rb +1348 -0
  118. data/lib/laser/standard_library/string.rb +666 -0
  119. data/lib/laser/standard_library/stringio.rb +2 -0
  120. data/lib/laser/standard_library/symbol.rb +125 -0
  121. data/lib/laser/standard_library/tsort.rb +242 -0
  122. data/lib/laser/support/acts_as_struct.rb +66 -0
  123. data/lib/laser/support/frequency.rb +55 -0
  124. data/lib/laser/support/inheritable_attributes.rb +145 -0
  125. data/lib/laser/support/module_extensions.rb +94 -0
  126. data/lib/laser/support/placeholder_object.rb +13 -0
  127. data/lib/laser/third_party/rgl/adjacency.rb +221 -0
  128. data/lib/laser/third_party/rgl/base.rb +228 -0
  129. data/lib/laser/third_party/rgl/bidirectional.rb +39 -0
  130. data/lib/laser/third_party/rgl/condensation.rb +47 -0
  131. data/lib/laser/third_party/rgl/connected_components.rb +138 -0
  132. data/lib/laser/third_party/rgl/control_flow.rb +170 -0
  133. data/lib/laser/third_party/rgl/depth_first_spanning_tree.rb +37 -0
  134. data/lib/laser/third_party/rgl/dominators.rb +124 -0
  135. data/lib/laser/third_party/rgl/dot.rb +93 -0
  136. data/lib/laser/third_party/rgl/graphxml.rb +51 -0
  137. data/lib/laser/third_party/rgl/implicit.rb +174 -0
  138. data/lib/laser/third_party/rgl/mutable.rb +117 -0
  139. data/lib/laser/third_party/rgl/rdot.rb +445 -0
  140. data/lib/laser/third_party/rgl/topsort.rb +72 -0
  141. data/lib/laser/third_party/rgl/transitivity.rb +180 -0
  142. data/lib/laser/third_party/rgl/traversal.rb +348 -0
  143. data/lib/laser/types/types.rb +433 -0
  144. data/lib/laser/version.rb +14 -0
  145. data/lib/laser/warning.rb +149 -0
  146. data/lib/laser/warning_sets/default.yml +13 -0
  147. data/lib/laser/warnings/assignment_in_condition.rb +20 -0
  148. data/lib/laser/warnings/comment_spacing.rb +31 -0
  149. data/lib/laser/warnings/extra_blank_lines.rb +30 -0
  150. data/lib/laser/warnings/extra_whitespace.rb +16 -0
  151. data/lib/laser/warnings/hash_symbol_18_warning.rb +63 -0
  152. data/lib/laser/warnings/hash_symbol_19_warning.rb +29 -0
  153. data/lib/laser/warnings/line_length.rb +115 -0
  154. data/lib/laser/warnings/misaligned_unindentation.rb +17 -0
  155. data/lib/laser/warnings/operator_spacing.rb +68 -0
  156. data/lib/laser/warnings/parens_on_declaration.rb +30 -0
  157. data/lib/laser/warnings/rescue_exception.rb +42 -0
  158. data/lib/laser/warnings/semicolon.rb +25 -0
  159. data/lib/laser/warnings/sexp_errors.rb +24 -0
  160. data/lib/laser/warnings/uncalled_method_warning.rb +7 -0
  161. data/lib/laser/warnings/useless_double_quotes.rb +38 -0
  162. data/spec/analysis_specs/annotations_spec.rb +47 -0
  163. data/spec/analysis_specs/annotations_specs/comment_attachment_spec.rb +68 -0
  164. data/spec/analysis_specs/annotations_specs/node_pointers_annotation_spec.rb +90 -0
  165. data/spec/analysis_specs/annotations_specs/runtime_annotation_spec.rb +135 -0
  166. data/spec/analysis_specs/annotations_specs/spec_helper.rb +33 -0
  167. data/spec/analysis_specs/argument_expansion_spec.rb +113 -0
  168. data/spec/analysis_specs/bindings_spec.rb +36 -0
  169. data/spec/analysis_specs/comment_spec.rb +93 -0
  170. data/spec/analysis_specs/control_flow_specs/cfg_instruction_spec.rb +111 -0
  171. data/spec/analysis_specs/control_flow_specs/constant_propagation_spec.rb +560 -0
  172. data/spec/analysis_specs/control_flow_specs/control_flow_graph_spec.rb +5 -0
  173. data/spec/analysis_specs/control_flow_specs/raise_properties_spec.rb +310 -0
  174. data/spec/analysis_specs/control_flow_specs/raise_type_inference_spec.rb +301 -0
  175. data/spec/analysis_specs/control_flow_specs/return_type_inference_spec.rb +431 -0
  176. data/spec/analysis_specs/control_flow_specs/simulation_spec.rb +158 -0
  177. data/spec/analysis_specs/control_flow_specs/spec_helper.rb +110 -0
  178. data/spec/analysis_specs/control_flow_specs/tuple_misuse_inference_spec.rb +125 -0
  179. data/spec/analysis_specs/control_flow_specs/unreachability_analysis_spec.rb +76 -0
  180. data/spec/analysis_specs/control_flow_specs/unused_variable_spec.rb +99 -0
  181. data/spec/analysis_specs/control_flow_specs/yield_properties_spec.rb +372 -0
  182. data/spec/analysis_specs/error_spec.rb +30 -0
  183. data/spec/analysis_specs/laser_class_spec.rb +322 -0
  184. data/spec/analysis_specs/lexical_analysis_spec.rb +184 -0
  185. data/spec/analysis_specs/protocol_registry_spec.rb +63 -0
  186. data/spec/analysis_specs/scope_annotation_spec.rb +1013 -0
  187. data/spec/analysis_specs/scope_spec.rb +126 -0
  188. data/spec/analysis_specs/sexp_analysis_spec.rb +30 -0
  189. data/spec/analysis_specs/sexp_extension_specs/constant_extraction_spec.rb +309 -0
  190. data/spec/analysis_specs/sexp_extension_specs/source_location_spec.rb +231 -0
  191. data/spec/analysis_specs/sexp_extension_specs/spec_helper.rb +1 -0
  192. data/spec/analysis_specs/sexp_extension_specs/type_inference_spec.rb +252 -0
  193. data/spec/analysis_specs/sexp_spec.rb +167 -0
  194. data/spec/analysis_specs/spec_helper.rb +27 -0
  195. data/spec/analysis_specs/unused_methods_spec.rb +65 -0
  196. data/spec/analysis_specs/visitor_spec.rb +64 -0
  197. data/spec/annotation_parser_specs/annotations_parser_spec.rb +89 -0
  198. data/spec/annotation_parser_specs/class_annotation_parser_spec.rb +120 -0
  199. data/spec/annotation_parser_specs/overload_parser_spec.rb +39 -0
  200. data/spec/annotation_parser_specs/parsers_spec.rb +14 -0
  201. data/spec/annotation_parser_specs/spec_helper.rb +1 -0
  202. data/spec/annotation_parser_specs/structural_parser_spec.rb +67 -0
  203. data/spec/laser_spec.rb +14 -0
  204. data/spec/rake_specs/spec_helper.rb +1 -0
  205. data/spec/rake_specs/task_spec.rb +67 -0
  206. data/spec/runner_spec.rb +207 -0
  207. data/spec/scanner_spec.rb +75 -0
  208. data/spec/spec_helper.rb +121 -0
  209. data/spec/standard_library/exceptions_spec.rb +19 -0
  210. data/spec/standard_library/globals_spec.rb +14 -0
  211. data/spec/standard_library/set_spec.rb +31 -0
  212. data/spec/standard_library/spec_helper.rb +1 -0
  213. data/spec/standard_library/standard_library_spec.rb +302 -0
  214. data/spec/support_specs/acts_as_struct_spec.rb +94 -0
  215. data/spec/support_specs/frequency_spec.rb +23 -0
  216. data/spec/support_specs/module_extensions_spec.rb +117 -0
  217. data/spec/support_specs/spec_helper.rb +1 -0
  218. data/spec/type_specs/spec_helper.rb +1 -0
  219. data/spec/type_specs/types_spec.rb +133 -0
  220. data/spec/warning_spec.rb +95 -0
  221. data/spec/warning_specs/assignment_in_condition_spec.rb +68 -0
  222. data/spec/warning_specs/comment_spacing_spec.rb +65 -0
  223. data/spec/warning_specs/extra_blank_lines_spec.rb +70 -0
  224. data/spec/warning_specs/extra_whitespace_spec.rb +33 -0
  225. data/spec/warning_specs/hash_symbol_18_warning_spec.rb +89 -0
  226. data/spec/warning_specs/hash_symbol_19_warning_spec.rb +63 -0
  227. data/spec/warning_specs/line_length_spec.rb +173 -0
  228. data/spec/warning_specs/misaligned_unindentation_spec.rb +35 -0
  229. data/spec/warning_specs/operator_spacing_spec.rb +104 -0
  230. data/spec/warning_specs/parens_on_declaration_spec.rb +57 -0
  231. data/spec/warning_specs/rescue_exception_spec.rb +105 -0
  232. data/spec/warning_specs/semicolon_spec.rb +58 -0
  233. data/spec/warning_specs/spec_helper.rb +1 -0
  234. data/spec/warning_specs/useless_double_quotes_spec.rb +74 -0
  235. data/status_reports/2010/12/2010-12-14.md +163 -0
  236. data/status_reports/2010/12/2010-12-23.md +298 -0
  237. data/status_reports/2010/12/2010-12-24.md +6 -0
  238. data/test/third_party_tests/rgl_tests/TestComponents.rb +65 -0
  239. data/test/third_party_tests/rgl_tests/TestCycles.rb +61 -0
  240. data/test/third_party_tests/rgl_tests/TestDirectedGraph.rb +125 -0
  241. data/test/third_party_tests/rgl_tests/TestDot.rb +18 -0
  242. data/test/third_party_tests/rgl_tests/TestEdge.rb +34 -0
  243. data/test/third_party_tests/rgl_tests/TestGraph.rb +71 -0
  244. data/test/third_party_tests/rgl_tests/TestGraphXML.rb +57 -0
  245. data/test/third_party_tests/rgl_tests/TestImplicit.rb +52 -0
  246. data/test/third_party_tests/rgl_tests/TestRdot.rb +863 -0
  247. data/test/third_party_tests/rgl_tests/TestTransitivity.rb +129 -0
  248. data/test/third_party_tests/rgl_tests/TestTraversal.rb +220 -0
  249. data/test/third_party_tests/rgl_tests/TestUnDirectedGraph.rb +102 -0
  250. data/test/third_party_tests/rgl_tests/examples/north/Graph.log +128 -0
  251. data/test/third_party_tests/rgl_tests/examples/north/g.10.0.graphml +28 -0
  252. data/test/third_party_tests/rgl_tests/examples/north/g.10.1.graphml +28 -0
  253. data/test/third_party_tests/rgl_tests/examples/north/g.10.11.graphml +31 -0
  254. data/test/third_party_tests/rgl_tests/examples/north/g.10.12.graphml +27 -0
  255. data/test/third_party_tests/rgl_tests/examples/north/g.10.13.graphml +27 -0
  256. data/test/third_party_tests/rgl_tests/examples/north/g.10.14.graphml +27 -0
  257. data/test/third_party_tests/rgl_tests/examples/north/g.10.15.graphml +26 -0
  258. data/test/third_party_tests/rgl_tests/examples/north/g.10.16.graphml +26 -0
  259. data/test/third_party_tests/rgl_tests/examples/north/g.10.17.graphml +26 -0
  260. data/test/third_party_tests/rgl_tests/examples/north/g.10.19.graphml +37 -0
  261. data/test/third_party_tests/rgl_tests/examples/north/g.10.2.graphml +28 -0
  262. data/test/third_party_tests/rgl_tests/examples/north/g.10.20.graphml +38 -0
  263. data/test/third_party_tests/rgl_tests/examples/north/g.10.22.graphml +43 -0
  264. data/test/third_party_tests/rgl_tests/examples/north/g.10.24.graphml +30 -0
  265. data/test/third_party_tests/rgl_tests/examples/north/g.10.25.graphml +45 -0
  266. data/test/third_party_tests/rgl_tests/examples/north/g.10.27.graphml +38 -0
  267. data/test/third_party_tests/rgl_tests/examples/north/g.10.28.graphml +30 -0
  268. data/test/third_party_tests/rgl_tests/examples/north/g.10.29.graphml +38 -0
  269. data/test/third_party_tests/rgl_tests/examples/north/g.10.3.graphml +26 -0
  270. data/test/third_party_tests/rgl_tests/examples/north/g.10.30.graphml +34 -0
  271. data/test/third_party_tests/rgl_tests/examples/north/g.10.31.graphml +42 -0
  272. data/test/third_party_tests/rgl_tests/examples/north/g.10.34.graphml +42 -0
  273. data/test/third_party_tests/rgl_tests/examples/north/g.10.37.graphml +28 -0
  274. data/test/third_party_tests/rgl_tests/examples/north/g.10.38.graphml +38 -0
  275. data/test/third_party_tests/rgl_tests/examples/north/g.10.39.graphml +36 -0
  276. data/test/third_party_tests/rgl_tests/examples/north/g.10.4.graphml +26 -0
  277. data/test/third_party_tests/rgl_tests/examples/north/g.10.40.graphml +37 -0
  278. data/test/third_party_tests/rgl_tests/examples/north/g.10.41.graphml +37 -0
  279. data/test/third_party_tests/rgl_tests/examples/north/g.10.42.graphml +26 -0
  280. data/test/third_party_tests/rgl_tests/examples/north/g.10.45.graphml +28 -0
  281. data/test/third_party_tests/rgl_tests/examples/north/g.10.46.graphml +32 -0
  282. data/test/third_party_tests/rgl_tests/examples/north/g.10.5.graphml +31 -0
  283. data/test/third_party_tests/rgl_tests/examples/north/g.10.50.graphml +30 -0
  284. data/test/third_party_tests/rgl_tests/examples/north/g.10.56.graphml +29 -0
  285. data/test/third_party_tests/rgl_tests/examples/north/g.10.57.graphml +32 -0
  286. data/test/third_party_tests/rgl_tests/examples/north/g.10.58.graphml +32 -0
  287. data/test/third_party_tests/rgl_tests/examples/north/g.10.6.graphml +26 -0
  288. data/test/third_party_tests/rgl_tests/examples/north/g.10.60.graphml +32 -0
  289. data/test/third_party_tests/rgl_tests/examples/north/g.10.61.graphml +34 -0
  290. data/test/third_party_tests/rgl_tests/examples/north/g.10.62.graphml +34 -0
  291. data/test/third_party_tests/rgl_tests/examples/north/g.10.68.graphml +30 -0
  292. data/test/third_party_tests/rgl_tests/examples/north/g.10.69.graphml +32 -0
  293. data/test/third_party_tests/rgl_tests/examples/north/g.10.7.graphml +29 -0
  294. data/test/third_party_tests/rgl_tests/examples/north/g.10.70.graphml +26 -0
  295. data/test/third_party_tests/rgl_tests/examples/north/g.10.71.graphml +27 -0
  296. data/test/third_party_tests/rgl_tests/examples/north/g.10.72.graphml +28 -0
  297. data/test/third_party_tests/rgl_tests/examples/north/g.10.74.graphml +29 -0
  298. data/test/third_party_tests/rgl_tests/examples/north/g.10.75.graphml +29 -0
  299. data/test/third_party_tests/rgl_tests/examples/north/g.10.78.graphml +27 -0
  300. data/test/third_party_tests/rgl_tests/examples/north/g.10.79.graphml +34 -0
  301. data/test/third_party_tests/rgl_tests/examples/north/g.10.8.graphml +29 -0
  302. data/test/third_party_tests/rgl_tests/examples/north/g.10.80.graphml +34 -0
  303. data/test/third_party_tests/rgl_tests/examples/north/g.10.82.graphml +35 -0
  304. data/test/third_party_tests/rgl_tests/examples/north/g.10.83.graphml +32 -0
  305. data/test/third_party_tests/rgl_tests/examples/north/g.10.85.graphml +34 -0
  306. data/test/third_party_tests/rgl_tests/examples/north/g.10.86.graphml +34 -0
  307. data/test/third_party_tests/rgl_tests/examples/north/g.10.88.graphml +37 -0
  308. data/test/third_party_tests/rgl_tests/examples/north/g.10.89.graphml +29 -0
  309. data/test/third_party_tests/rgl_tests/examples/north/g.10.9.graphml +26 -0
  310. data/test/third_party_tests/rgl_tests/examples/north/g.10.90.graphml +32 -0
  311. data/test/third_party_tests/rgl_tests/examples/north/g.10.91.graphml +31 -0
  312. data/test/third_party_tests/rgl_tests/examples/north/g.10.92.graphml +26 -0
  313. data/test/third_party_tests/rgl_tests/examples/north/g.10.93.graphml +32 -0
  314. data/test/third_party_tests/rgl_tests/examples/north/g.10.94.graphml +34 -0
  315. data/test/third_party_tests/rgl_tests/examples/north/g.12.8.graphml +40 -0
  316. data/test/third_party_tests/rgl_tests/examples/north/g.14.9.graphml +36 -0
  317. data/test/third_party_tests/rgl_tests/test_helper.rb +7 -0
  318. data/test/third_party_tests/test_inheritable_attributes.rb +187 -0
  319. metadata +470 -0
@@ -0,0 +1,68 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe AssignmentInConditionWarning do
4
+ it 'is a file-based warning' do
5
+ AssignmentInConditionWarning.new('(stdin)', 'hello').should be_a(FileWarning)
6
+ end
7
+
8
+ context 'in an if condition' do
9
+ it 'matches when the only condition is an unwrapped assignment' do
10
+ AssignmentInConditionWarning.should warn('if x = 5; end')
11
+ end
12
+
13
+ it 'does not match if the simple assignment is wrapped in parentheses' do
14
+ AssignmentInConditionWarning.should_not warn('if (x = 5); end')
15
+ end
16
+
17
+ it 'matches in a complex expression which contains an assignment' do
18
+ AssignmentInConditionWarning.should warn('if (x && y) || x = 5; end')
19
+ end
20
+ end
21
+
22
+ context 'in an elseif condition' do
23
+ it 'matches when the only condition is an unwrapped assignment' do
24
+ AssignmentInConditionWarning.should warn('if true; elsif x = 5; end')
25
+ end
26
+
27
+ it 'does not match if the simple assignment is wrapped in parentheses' do
28
+ AssignmentInConditionWarning.should_not warn('if true; elsif (x = 5); end')
29
+ end
30
+
31
+ it 'matches in a complex expression which contains an assignment' do
32
+ AssignmentInConditionWarning.should warn('if true; elsif (x && y) || x = 5; end')
33
+ end
34
+ end
35
+
36
+ context 'in an unless condition' do
37
+ it 'matches when the only condition is an unwrapped assignment' do
38
+ AssignmentInConditionWarning.should warn('unless x = 5; end')
39
+ end
40
+
41
+ it 'does not match if the simple assignment is wrapped in parentheses' do
42
+ AssignmentInConditionWarning.should_not warn('unless (x = 5); end')
43
+ end
44
+
45
+ it 'matches in a complex expression which contains an assignment' do
46
+ AssignmentInConditionWarning.should warn('unless (x && y) || x = 5; end')
47
+ end
48
+ end
49
+
50
+ it 'is not fooled when the entire if expression is in parentheses' do
51
+ AssignmentInConditionWarning.should warn('(if true; elsif x = 5; end)')
52
+ end
53
+
54
+ # it 'does not match when arguments are surrounded by parentheses' do
55
+ # AssignmentInConditionWarning.should_not warn('def abc(arg); end')
56
+ # end
57
+ #
58
+ # it 'does not match when there are no arguments' do
59
+ # AssignmentInConditionWarning.should_not warn('def abc; end')
60
+ # end
61
+ #
62
+ # describe '#desc' do
63
+ # it 'includes the name of the offending method' do
64
+ # matches = AssignmentInConditionWarning.new('(stdin)', 'def silly_monkey arg1, *rest; end').match?
65
+ # matches[0].desc.should =~ /silly_monkey/
66
+ # end
67
+ # end
68
+ end
@@ -0,0 +1,65 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe InlineCommentSpaceWarning do
4
+ SETTINGS = {InlineCommentSpaceWarning::OPTION_KEY => 2, :indent_size => 2}
5
+ it 'is a line-based warning' do
6
+ InlineCommentSpaceWarning.new('(stdin)', 'hello').should be_a(LineWarning)
7
+ end
8
+
9
+ it 'matches when there are less than 2 spaces between code and comment' do
10
+ InlineCommentSpaceWarning.should warn('a + b#comment', SETTINGS)
11
+ InlineCommentSpaceWarning.should warn('a + b # comment', SETTINGS)
12
+ InlineCommentSpaceWarning.should_not warn('a + b # comment', SETTINGS)
13
+ InlineCommentSpaceWarning.should_not warn('a +b # laser: ignore OperatorSpacing', SETTINGS)
14
+ end
15
+
16
+ it 'has an option to specify the necessary spacing' do
17
+ InlineCommentSpaceWarning.options.size.should be > 0
18
+ InlineCommentSpaceWarning.options[0].first.should ==
19
+ InlineCommentSpaceWarning::OPTION_KEY
20
+ end
21
+
22
+ it 'respects the option for specifying the necessary spacing' do
23
+ settings = {InlineCommentSpaceWarning::OPTION_KEY => 0}
24
+ InlineCommentSpaceWarning.should warn('a + b # comment', settings)
25
+ InlineCommentSpaceWarning.should_not warn('a + b# comment', settings)
26
+ end
27
+
28
+ it 'should not warn for improperly spaced comments that are inside comments' do
29
+ InlineCommentSpaceWarning.should_not warn('#a + b # comment', SETTINGS)
30
+ end
31
+
32
+ it 'should not warn for an empty comment at the start of a line' do
33
+ InlineCommentSpaceWarning.should_not warn('#', SETTINGS)
34
+ end
35
+
36
+ it 'has a remotely useful description' do
37
+ InlineCommentSpaceWarning.new('(stdin)', 'hello #').desc.should =~ /inline.*comment/i
38
+ end
39
+
40
+ describe 'when fixing' do
41
+ before do
42
+ @settings = {InlineCommentSpaceWarning::OPTION_KEY => 2}
43
+ end
44
+
45
+ after do
46
+ InlineCommentSpaceWarning.should correct_to(@input, @output, @settings)
47
+ end
48
+
49
+ it 'adds spaces when necessary' do
50
+ @input = 'a + b#comment'
51
+ @output = 'a + b #comment'
52
+ end
53
+
54
+ it 'removes spaces when necessary' do
55
+ @input = 'a + b #comment'
56
+ @output = 'a + b #comment'
57
+ end
58
+
59
+ it 'respects the option for spacing' do
60
+ @settings = {InlineCommentSpaceWarning::OPTION_KEY => 0}
61
+ @input = 'a + b #comment'
62
+ @output = 'a + b#comment'
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,70 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe ExtraBlankLinesWarning do
4
+ it 'is a file-based warning' do
5
+ ExtraBlankLinesWarning.new('(stdin)', 'hello').should be_a(FileWarning)
6
+ FileWarning.all_warnings.should include(ExtraBlankLinesWarning)
7
+ end
8
+
9
+ it 'matches when there is a single empty blank line' do
10
+ ExtraBlankLinesWarning.should warn("a + b\n")
11
+ end
12
+
13
+ it 'matches when there is a single blank line with spaces' do
14
+ ExtraBlankLinesWarning.should warn("a + b\n ")
15
+ end
16
+
17
+ it 'matches when there is are multiple blank lines' do
18
+ ExtraBlankLinesWarning.should warn("a + b\n \n\t\n")
19
+ end
20
+
21
+ it 'counts the number of blank lines' do
22
+ ExtraBlankLinesWarning.new('(stdin)', "a + b\n").count_extra_lines.should == 1
23
+ ExtraBlankLinesWarning.new('(stdin)', "a + b\n\t\n").count_extra_lines.should == 2
24
+ ExtraBlankLinesWarning.new('(stdin)', "a + b\n\n").count_extra_lines.should == 2
25
+ ExtraBlankLinesWarning.new('(stdin)', "a + b\n \n\n").count_extra_lines.should == 3
26
+ ExtraBlankLinesWarning.new('(stdin)', "a + b\n \n\t\n").count_extra_lines.should == 3
27
+ ExtraBlankLinesWarning.new('(stdin)', "a + b\n\n\n\n\n").count_extra_lines.should == 5
28
+ end
29
+
30
+ it 'has a remotely useful description' do
31
+ ExtraBlankLinesWarning.new('(stdin)', 'hello ').desc.should =~ /blank line/
32
+ end
33
+
34
+ INPUTS = ["a + b\n\n\t \t\n\t ", "a + b\n \n\t\n", "a + b\n \n\n",
35
+ "a + b\n\n\n\n\n", "a + b\n", "a + b\n " ]
36
+
37
+ INPUTS.each do |input|
38
+ describe "When fixing #{input.inspect}" do
39
+ it 'fixes by removing all extra whitespace' do
40
+ ExtraBlankLinesWarning.should correct_to(input, 'a + b')
41
+ end
42
+ end
43
+ end
44
+
45
+ describe 'when fixing a realistic multiline block' do
46
+ before do
47
+ @original = <<-EOF
48
+ # Warning for using semicolons outside of class declarations.
49
+ class SemicolonWarning < LineWarning
50
+
51
+ def initialize(file, line)
52
+ severity = line =~ /['"]/ ? 2 : 4
53
+ super('Semicolon for multiple statements', file, line, 0, severity)
54
+ end
55
+
56
+ def desc
57
+ 'The line uses a semicolon to separate multiple statements outside of a class declaration.'
58
+ end
59
+
60
+ end
61
+ EOF
62
+ @original.strip!
63
+ @invalid = @original + "\n \t\t\n \n\n"
64
+ end
65
+
66
+ it 'only removes the trailing whitespace' do
67
+ ExtraBlankLinesWarning.should correct_to(@invalid, @original)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,33 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe ExtraWhitespaceWarning do
4
+ it 'is a line-based warning' do
5
+ ExtraWhitespaceWarning.new('(stdin)', 'hello').should be_a(LineWarning)
6
+ end
7
+
8
+ it 'matches when there are spaces at the end of a line' do
9
+ ExtraWhitespaceWarning.should warn('a + b ')
10
+ ExtraWhitespaceWarning.should warn('a + b ')
11
+ ExtraWhitespaceWarning.should_not warn('a + b')
12
+ end
13
+
14
+ it 'matches when there are tabs at the end of a line' do
15
+ ExtraWhitespaceWarning.should warn("a + b\t\t")
16
+ ExtraWhitespaceWarning.should warn("a + b\t")
17
+ ExtraWhitespaceWarning.should_not warn('a + b')
18
+ end
19
+
20
+ it 'has a remotely useful description' do
21
+ ExtraWhitespaceWarning.new('(stdin)', 'hello ').desc.should =~ /whitespace/
22
+ end
23
+
24
+ describe 'when fixing' do
25
+ it 'fixes by removing extra spaces' do
26
+ ExtraWhitespaceWarning.should correct_to('a + b ', 'a + b')
27
+ end
28
+
29
+ it 'fixes by removing extra tabs' do
30
+ ExtraWhitespaceWarning.should correct_to("a + b\t\t", 'a + b')
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,89 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe HashSymbol18Warning do
4
+ it 'is a file-based warning' do
5
+ HashSymbol18Warning.new('(stdin)', 'hello').should be_a(FileWarning)
6
+ end
7
+
8
+ it 'matches against a 1.8-style hash' do
9
+ HashSymbol18Warning.should warn('x = { :foo => bar }')
10
+ end
11
+
12
+ it 'does not match against a 1.9-style hash' do
13
+ HashSymbol18Warning.should_not warn('x = { foo: bar }')
14
+ end
15
+
16
+ it 'matches against a multiline 1.8-style hash' do
17
+ HashSymbol18Warning.should warn('x = { :foo =>
18
+ bar }')
19
+ end
20
+
21
+ it 'does not match against a multiline 1.9-style hash' do
22
+ HashSymbol18Warning.should_not warn('x = { foo:
23
+ bar }')
24
+ end
25
+
26
+ describe '#fix' do
27
+ it 'fixes a simple 1.8-style single-keyed hash to 1.9-style hash keys' do
28
+ input = <<-EOF
29
+ x = { :foo => bar }
30
+ EOF
31
+ output = <<-EOF
32
+ x = { foo: bar }
33
+ EOF
34
+ HashSymbol18Warning.new('(stdin)', input).match?(input).first.fix.should == output
35
+ end
36
+
37
+ it 'fixes many 1.8-style hash keys into 1.9-style hash keys' do
38
+ input = %q{
39
+ with_jumps_redirected(:break => ensure_body[1], :redo => ensure_body[1], :next => ensure_body[1],
40
+ :return => ensure_body[1], :rescue => ensure_body[1],
41
+ :yield_fail => ensure_body[1]) do
42
+ rescue_target, yield_fail_target =
43
+ build_rescue_target(node, result, rescue_body, ensure_block,
44
+ current_rescue, current_yield_fail)
45
+ walk_body_with_rescue_target(result, body, body_block, rescue_target, yield_fail_target)
46
+ end
47
+ }
48
+ output = %q{
49
+ with_jumps_redirected(break: ensure_body[1], redo: ensure_body[1], next: ensure_body[1],
50
+ return: ensure_body[1], rescue: ensure_body[1],
51
+ yield_fail: ensure_body[1]) do
52
+ rescue_target, yield_fail_target =
53
+ build_rescue_target(node, result, rescue_body, ensure_block,
54
+ current_rescue, current_yield_fail)
55
+ walk_body_with_rescue_target(result, body, body_block, rescue_target, yield_fail_target)
56
+ end
57
+ }
58
+ HashSymbol18Warning.new('(stdin)', input).match?(input).inject(input) do |input, warning|
59
+ warning.fix(input)
60
+ end.should == output
61
+ end
62
+
63
+ it 'fixes many 1.8-style hash keys into 1.9-style hash keys despite spacing' do
64
+ input = %q{
65
+ with_jumps_redirected(:break=>ensure_body[1], :redo=>ensure_body[1], :next=>ensure_body[1],
66
+ :return=>ensure_body[1], :rescue=>ensure_body[1],
67
+ :yield_fail=>ensure_body[1]) do
68
+ rescue_target, yield_fail_target =
69
+ build_rescue_target(node, result, rescue_body, ensure_block,
70
+ current_rescue, current_yield_fail)
71
+ walk_body_with_rescue_target(result, body, body_block, rescue_target, yield_fail_target)
72
+ end
73
+ }
74
+ output = %q{
75
+ with_jumps_redirected(break:ensure_body[1], redo:ensure_body[1], next:ensure_body[1],
76
+ return:ensure_body[1], rescue:ensure_body[1],
77
+ yield_fail:ensure_body[1]) do
78
+ rescue_target, yield_fail_target =
79
+ build_rescue_target(node, result, rescue_body, ensure_block,
80
+ current_rescue, current_yield_fail)
81
+ walk_body_with_rescue_target(result, body, body_block, rescue_target, yield_fail_target)
82
+ end
83
+ }
84
+ HashSymbol18Warning.new('(stdin)', input).match?(input).inject(input) do |input, warning|
85
+ warning.fix(input)
86
+ end.should == output
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,63 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe HashSymbol19Warning do
4
+ it 'is a file-based warning' do
5
+ HashSymbol19Warning.new('(stdin)', 'hello').should be_a(FileWarning)
6
+ end
7
+
8
+ it 'matches against a 1.8-style hash' do
9
+ HashSymbol19Warning.should_not warn('x = { :foo => bar }')
10
+ end
11
+
12
+ it 'does not match against a 1.9-style hash' do
13
+ HashSymbol19Warning.should warn('x = { foo: bar }')
14
+ end
15
+
16
+ it 'matches against a multiline 1.8-style hash' do
17
+ HashSymbol19Warning.should_not warn('x = { :foo =>
18
+ bar }')
19
+ end
20
+
21
+ it 'does not match against a multiline 1.9-style hash' do
22
+ HashSymbol19Warning.should warn('x = { foo:
23
+ bar }')
24
+ end
25
+
26
+ describe '#fix' do
27
+ it 'fixes a simple 1.8-style single-keyed hash to 1.9-style hash keys' do
28
+ input = <<-EOF
29
+ x = { foo: bar }
30
+ EOF
31
+ output = <<-EOF
32
+ x = { :foo => bar }
33
+ EOF
34
+ HashSymbol19Warning.new('(stdin)', input).match?(input).first.fix.should == output
35
+ end
36
+
37
+ it 'fixes many 1.8-style hash keys into 1.9-style hash keys' do
38
+ input = %q{
39
+ with_jumps_redirected(break: ensure_body[1], redo: ensure_body[1], next: ensure_body[1],
40
+ return: ensure_body[1], rescue: ensure_body[1],
41
+ yield_fail: ensure_body[1]) do
42
+ rescue_target, yield_fail_target =
43
+ build_rescue_target(node, result, rescue_body, ensure_block,
44
+ current_rescue, current_yield_fail)
45
+ walk_body_with_rescue_target(result, body, body_block, rescue_target, yield_fail_target)
46
+ end
47
+ }
48
+ output = %q{
49
+ with_jumps_redirected(:break => ensure_body[1], :redo => ensure_body[1], :next => ensure_body[1],
50
+ :return => ensure_body[1], :rescue => ensure_body[1],
51
+ :yield_fail => ensure_body[1]) do
52
+ rescue_target, yield_fail_target =
53
+ build_rescue_target(node, result, rescue_body, ensure_block,
54
+ current_rescue, current_yield_fail)
55
+ walk_body_with_rescue_target(result, body, body_block, rescue_target, yield_fail_target)
56
+ end
57
+ }
58
+ HashSymbol19Warning.new('(stdin)', input).match?(input).inject(input) do |input, warning|
59
+ warning.fix(input)
60
+ end.should == output
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,173 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe GenericLineLengthWarning do
4
+ before do
5
+ @eighty_cap = LineLengthCustomSeverity(80, 2)
6
+ @eighty_cap.line_length_limit = 80
7
+ end
8
+
9
+ it 'is a line-based warning' do
10
+ GenericLineLengthWarning.new('(stdin)', 'hello').should be_a(LineWarning)
11
+ end
12
+
13
+ it 'initializes to a file and line' do
14
+ warning = @eighty_cap.new('(stdin)', 'x' * 81)
15
+ warning.severity.should == @eighty_cap.severity
16
+ end
17
+
18
+ describe '#desc' do
19
+ it 'has a remotely useful description' do
20
+ @eighty_cap.new('(stdin)', 'x' * 80).desc.should =~ /line length/i
21
+ end
22
+ end
23
+
24
+ describe '#inspect' do
25
+ it 'contains the capacity in the description' do
26
+ @eighty_cap.inspect.should =~ /80/i
27
+ end
28
+ end
29
+
30
+ it 'matches lines longer than the specified number of characters' do
31
+ @eighty_cap.should warn('x' * 82)
32
+ end
33
+
34
+ it 'does not match lines shorter than the specified number of characters' do
35
+ @eighty_cap.should_not warn('x' * 78)
36
+ end
37
+
38
+ it 'does not match lines equal to the specified number of characters' do
39
+ @eighty_cap.should_not warn('x' * 80)
40
+ end
41
+
42
+ describe 'when fixing' do
43
+ before do
44
+ @twenty_cap = Class.new(GenericLineLengthWarning)
45
+ @twenty_cap.line_length_limit = 20
46
+ @settings = {}
47
+ end
48
+
49
+ after do
50
+ @twenty_cap.should correct_to(@input, @output, @settings)
51
+ end
52
+
53
+ it 'takes a line with just a comment on it and breaks it into many lines' do
54
+ @input = '# my comment is this and that and another thing'
55
+ @output = "# my comment is this\n# and that and\n# another thing"
56
+ end
57
+
58
+ it 'creates new lines with the same indentation as the input' do
59
+ @input = ' # my comment is this and that and another thing'
60
+ @output = " # my comment is\n # this and that\n # and another\n # thing"
61
+ end
62
+
63
+ it 'uses the same number of hashes to denote the comment' do
64
+ @input = ' ## my comment is this and that and another thing'
65
+ @output = " ## my comment is\n ## this and that\n ## and another\n ## thing"
66
+ end
67
+
68
+ it 'splits up code with an overly long comment at the end' do
69
+ @input = ' a + b # this is a stupidly long comment lol'
70
+ @output = " # this is a\n # stupidly long\n # comment lol\n a + b"
71
+ end
72
+
73
+ it 'uses the same indentation and hashes for the new comment' do
74
+ @input = ' a + b ### this is a stupidly long comment lol'
75
+ @output = " ### this is a\n ### stupidly long\n ### comment lol\n a + b"
76
+ end
77
+
78
+ it 'fails to fix when if/unless are in a symbol' do
79
+ # This came from an actual bug from running laser on laser's source.
80
+ @input = " left, right = @class.new('').split_on_keyword('x = 5 unless y == 2', :unless)"
81
+ @output = @input
82
+ end
83
+
84
+ describe 'with an indent size of 2' do
85
+ before { @settings = {indent_size: 2} }
86
+ it "doesn't try to convert the 'end if foobar' technique" do
87
+ @input = ' end if should_run_block?'
88
+ @output = ' end if should_run_block?'
89
+ end
90
+
91
+ it "doesn't try to convert the 'end unless foobar' technique" do
92
+ @input = ' end unless should_run_block?'
93
+ @output = ' end unless should_run_block?'
94
+ end
95
+
96
+ it 'converts lines with guarded ifs into 3 liners' do
97
+ @input = 'puts x if x > y && y.call'
98
+ @output = "if x > y && y.call\n puts x\nend"
99
+ end
100
+
101
+ it 'converts lines with guarded unlesses into 3 liners' do
102
+ @input = 'puts x unless x > number'
103
+ @output = "unless x > number\n puts x\nend"
104
+ end
105
+
106
+ it 'converts lines with guarded ifs while maintaining indentation' do
107
+ @input = ' puts x unless x > number'
108
+ @output = " unless x > number\n puts x\n end"
109
+ end
110
+
111
+ it 'only converts when it finds a guard on the top level expression' do
112
+ @input = %Q[syms.each { |sym| raise ArgumentError, "unknown option '\#{sym}'" unless @specs[sym] }]
113
+ @output = %Q[syms.each { |sym| raise ArgumentError, "unknown option '\#{sym}'" unless @specs[sym] }]
114
+ end
115
+
116
+ it 'only converts when it finds a guard on the real-world top level expression' do
117
+ @input = 'x.select { |x| x if 5 }'
118
+ @output = 'x.select { |x| x if 5 }'
119
+ end
120
+
121
+ it 'converts nested if/unless as guards' do
122
+ @input = 'puts x if foo.bar unless baz.boo'
123
+ @output = "unless baz.boo\n if foo.bar\n puts x\n end\nend"
124
+ end
125
+
126
+ it 'converts nested three if/unless as guards' do
127
+ @input = 'puts x if foo.bar unless baz.boo if alpha.beta'
128
+ @output = "if alpha.beta\n unless baz.boo\n if foo.bar\n puts x\n end\n end\nend"
129
+ end
130
+
131
+ it 'converts nested three if/unless as guards maintaining indentation' do
132
+ @input = ' puts x if foo.bar unless baz.boo if alpha.beta'
133
+ @output = " if alpha.beta\n unless baz.boo\n if foo.bar\n puts x\n end\n end\n end"
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ describe 'LineLengthMaximum' do
140
+ before do
141
+ @hundred_cap = LineLengthMaximum(100)
142
+ end
143
+
144
+ it 'matches lines longer than the specified maximum' do
145
+ @hundred_cap.should warn('x' * 101)
146
+ end
147
+
148
+ it 'has a high severity' do
149
+ @hundred_cap.severity.should >= 7.5
150
+ end
151
+
152
+ it 'does not match lines smaller than the specified maximum' do
153
+ @hundred_cap.should_not warn('x' * 100)
154
+ end
155
+ end
156
+
157
+ describe 'LineLengthWarning' do
158
+ before do
159
+ @hundred_cap = LineLengthWarning(80)
160
+ end
161
+
162
+ it 'matches lines longer than the specified maximum' do
163
+ @hundred_cap.should warn('x' * 81)
164
+ end
165
+
166
+ it 'has a lower severity' do
167
+ @hundred_cap.severity.should <= 4
168
+ end
169
+
170
+ it 'does not match lines smaller than the specified maximum' do
171
+ @hundred_cap.should_not warn('x' * 80)
172
+ end
173
+ end