yard 0.9.18 → 0.9.19
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of yard might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.yardopts +26 -26
- data/CHANGELOG.md +742 -728
- data/LEGAL +66 -66
- data/LICENSE +22 -22
- data/README.md +328 -328
- data/Rakefile +42 -53
- data/benchmarks/builtins_vs_eval.rb +24 -24
- data/benchmarks/concat_vs_join.rb +13 -13
- data/benchmarks/erb_vs_erubis.rb +54 -54
- data/benchmarks/format_args.rb +47 -47
- data/benchmarks/generation.rb +38 -38
- data/benchmarks/marshal_vs_dbm.rb +64 -64
- data/benchmarks/parsing.rb +46 -46
- data/benchmarks/pathname_vs_string.rb +50 -50
- data/benchmarks/rdoc_vs_yardoc.rb +11 -11
- data/benchmarks/registry_store_types.rb +49 -49
- data/benchmarks/ri_vs_yri.rb +19 -19
- data/benchmarks/ripper_parser.rb +13 -13
- data/benchmarks/splat_vs_flatten.rb +13 -13
- data/benchmarks/template_erb.rb +23 -23
- data/benchmarks/template_format.rb +7 -7
- data/benchmarks/template_profile.rb +18 -18
- data/benchmarks/yri_cache.rb +20 -20
- data/bin/yard +13 -13
- data/bin/yardoc +13 -13
- data/bin/yri +13 -13
- data/docs/CodeObjects.md +115 -115
- data/docs/GettingStarted.md +679 -679
- data/docs/Handlers.md +152 -152
- data/docs/Overview.md +61 -61
- data/docs/Parser.md +191 -191
- data/docs/Tags.md +283 -283
- data/docs/TagsArch.md +123 -123
- data/docs/Templates.md +496 -496
- data/docs/WhatsNew.md +1245 -1245
- data/docs/templates/default/fulldoc/html/full_list_tag.erb +8 -8
- data/docs/templates/default/fulldoc/html/setup.rb +6 -6
- data/docs/templates/default/layout/html/setup.rb +9 -9
- data/docs/templates/default/layout/html/tag_list.erb +11 -11
- data/docs/templates/default/yard_tags/html/list.erb +18 -18
- data/docs/templates/default/yard_tags/html/setup.rb +26 -26
- data/docs/templates/plugin.rb +70 -70
- data/lib/rubygems_plugin.rb +9 -9
- data/lib/yard.rb +69 -69
- data/lib/yard/autoload.rb +308 -303
- data/lib/yard/cli/command.rb +85 -85
- data/lib/yard/cli/command_parser.rb +93 -93
- data/lib/yard/cli/config.rb +198 -198
- data/lib/yard/cli/diff.rb +270 -270
- data/lib/yard/cli/display.rb +69 -69
- data/lib/yard/cli/gems.rb +84 -84
- data/lib/yard/cli/graph.rb +125 -125
- data/lib/yard/cli/help.rb +20 -20
- data/lib/yard/cli/i18n.rb +70 -70
- data/lib/yard/cli/list.rb +23 -23
- data/lib/yard/cli/markup_types.rb +32 -32
- data/lib/yard/cli/server.rb +257 -257
- data/lib/yard/cli/stats.rb +231 -231
- data/lib/yard/cli/yardoc.rb +789 -788
- data/lib/yard/cli/yardopts_command.rb +110 -110
- data/lib/yard/cli/yri.rb +215 -215
- data/lib/yard/code_objects/base.rb +615 -615
- data/lib/yard/code_objects/class_object.rb +146 -146
- data/lib/yard/code_objects/class_variable_object.rb +11 -11
- data/lib/yard/code_objects/constant_object.rb +16 -16
- data/lib/yard/code_objects/extended_method_object.rb +24 -24
- data/lib/yard/code_objects/extra_file_object.rb +134 -131
- data/lib/yard/code_objects/macro_object.rb +172 -172
- data/lib/yard/code_objects/method_object.rb +196 -196
- data/lib/yard/code_objects/module_object.rb +21 -21
- data/lib/yard/code_objects/namespace_mapper.rb +114 -114
- data/lib/yard/code_objects/namespace_object.rb +200 -200
- data/lib/yard/code_objects/proxy.rb +240 -240
- data/lib/yard/code_objects/root_object.rb +19 -19
- data/lib/yard/config.rb +270 -270
- data/lib/yard/core_ext/array.rb +16 -16
- data/lib/yard/core_ext/file.rb +69 -69
- data/lib/yard/core_ext/hash.rb +16 -16
- data/lib/yard/core_ext/insertion.rb +63 -63
- data/lib/yard/core_ext/module.rb +11 -20
- data/lib/yard/core_ext/string.rb +68 -68
- data/lib/yard/core_ext/symbol_hash.rb +75 -75
- data/lib/yard/docstring.rb +386 -386
- data/lib/yard/docstring_parser.rb +345 -345
- data/lib/yard/gem_index.rb +29 -29
- data/lib/yard/globals.rb +22 -22
- data/lib/yard/handlers/base.rb +595 -595
- data/lib/yard/handlers/c/alias_handler.rb +16 -16
- data/lib/yard/handlers/c/attribute_handler.rb +13 -13
- data/lib/yard/handlers/c/base.rb +129 -129
- data/lib/yard/handlers/c/class_handler.rb +27 -27
- data/lib/yard/handlers/c/constant_handler.rb +13 -13
- data/lib/yard/handlers/c/handler_methods.rb +212 -211
- data/lib/yard/handlers/c/init_handler.rb +20 -20
- data/lib/yard/handlers/c/method_handler.rb +45 -45
- data/lib/yard/handlers/c/mixin_handler.rb +21 -21
- data/lib/yard/handlers/c/module_handler.rb +17 -17
- data/lib/yard/handlers/c/override_comment_handler.rb +31 -31
- data/lib/yard/handlers/c/path_handler.rb +11 -11
- data/lib/yard/handlers/c/struct_handler.rb +13 -13
- data/lib/yard/handlers/c/symbol_handler.rb +8 -8
- data/lib/yard/handlers/common/method_handler.rb +19 -0
- data/lib/yard/handlers/processor.rb +200 -200
- data/lib/yard/handlers/ruby/alias_handler.rb +44 -44
- data/lib/yard/handlers/ruby/attribute_handler.rb +87 -87
- data/lib/yard/handlers/ruby/base.rb +165 -165
- data/lib/yard/handlers/ruby/class_condition_handler.rb +92 -92
- data/lib/yard/handlers/ruby/class_handler.rb +119 -119
- data/lib/yard/handlers/ruby/class_variable_handler.rb +17 -17
- data/lib/yard/handlers/ruby/comment_handler.rb +10 -10
- data/lib/yard/handlers/ruby/constant_handler.rb +59 -59
- data/lib/yard/handlers/ruby/decorator_handler_methods.rb +123 -123
- data/lib/yard/handlers/ruby/dsl_handler.rb +15 -15
- data/lib/yard/handlers/ruby/dsl_handler_methods.rb +96 -96
- data/lib/yard/handlers/ruby/exception_handler.rb +27 -27
- data/lib/yard/handlers/ruby/extend_handler.rb +22 -22
- data/lib/yard/handlers/ruby/legacy/alias_handler.rb +37 -37
- data/lib/yard/handlers/ruby/legacy/attribute_handler.rb +65 -65
- data/lib/yard/handlers/ruby/legacy/base.rb +245 -245
- data/lib/yard/handlers/ruby/legacy/class_condition_handler.rb +83 -83
- data/lib/yard/handlers/ruby/legacy/class_handler.rb +113 -113
- data/lib/yard/handlers/ruby/legacy/class_variable_handler.rb +15 -15
- data/lib/yard/handlers/ruby/legacy/comment_handler.rb +10 -10
- data/lib/yard/handlers/ruby/legacy/constant_handler.rb +29 -29
- data/lib/yard/handlers/ruby/legacy/dsl_handler.rb +17 -17
- data/lib/yard/handlers/ruby/legacy/exception_handler.rb +13 -13
- data/lib/yard/handlers/ruby/legacy/extend_handler.rb +21 -21
- data/lib/yard/handlers/ruby/legacy/method_handler.rb +90 -90
- data/lib/yard/handlers/ruby/legacy/mixin_handler.rb +39 -39
- data/lib/yard/handlers/ruby/legacy/module_function_handler.rb +19 -19
- data/lib/yard/handlers/ruby/legacy/module_handler.rb +12 -12
- data/lib/yard/handlers/ruby/legacy/private_class_method_handler.rb +22 -22
- data/lib/yard/handlers/ruby/legacy/private_constant_handler.rb +22 -22
- data/lib/yard/handlers/ruby/legacy/visibility_handler.rb +17 -17
- data/lib/yard/handlers/ruby/legacy/yield_handler.rb +29 -29
- data/lib/yard/handlers/ruby/method_condition_handler.rb +9 -9
- data/lib/yard/handlers/ruby/method_handler.rb +114 -118
- data/lib/yard/handlers/ruby/mixin_handler.rb +37 -37
- data/lib/yard/handlers/ruby/module_function_handler.rb +27 -27
- data/lib/yard/handlers/ruby/module_handler.rb +12 -12
- data/lib/yard/handlers/ruby/private_class_method_handler.rb +14 -14
- data/lib/yard/handlers/ruby/private_constant_handler.rb +43 -43
- data/lib/yard/handlers/ruby/public_class_method_handler.rb +14 -14
- data/lib/yard/handlers/ruby/struct_handler_methods.rb +143 -143
- data/lib/yard/handlers/ruby/visibility_handler.rb +22 -22
- data/lib/yard/handlers/ruby/yield_handler.rb +31 -31
- data/lib/yard/i18n/locale.rb +67 -67
- data/lib/yard/i18n/message.rb +57 -57
- data/lib/yard/i18n/messages.rb +56 -56
- data/lib/yard/i18n/po_parser.rb +61 -61
- data/lib/yard/i18n/pot_generator.rb +290 -290
- data/lib/yard/i18n/text.rb +173 -173
- data/lib/yard/logging.rb +205 -205
- data/lib/yard/options.rb +217 -217
- data/lib/yard/parser/base.rb +57 -57
- data/lib/yard/parser/c/c_parser.rb +235 -235
- data/lib/yard/parser/c/comment_parser.rb +134 -134
- data/lib/yard/parser/c/statement.rb +64 -64
- data/lib/yard/parser/ruby/ast_node.rb +540 -540
- data/lib/yard/parser/ruby/legacy/ruby_lex.rb +1354 -1354
- data/lib/yard/parser/ruby/legacy/ruby_parser.rb +32 -32
- data/lib/yard/parser/ruby/legacy/statement.rb +66 -66
- data/lib/yard/parser/ruby/legacy/statement_list.rb +394 -394
- data/lib/yard/parser/ruby/legacy/token_list.rb +74 -74
- data/lib/yard/parser/ruby/ruby_parser.rb +687 -687
- data/lib/yard/parser/ruby/token_resolver.rb +156 -156
- data/lib/yard/parser/source_parser.rb +526 -526
- data/lib/yard/rake/yardoc_task.rb +81 -81
- data/lib/yard/registry.rb +439 -439
- data/lib/yard/registry_resolver.rb +189 -189
- data/lib/yard/registry_store.rb +337 -337
- data/lib/yard/rubygems/backports.rb +10 -10
- data/lib/yard/rubygems/backports/LICENSE.txt +57 -57
- data/lib/yard/rubygems/backports/MIT.txt +20 -20
- data/lib/yard/rubygems/backports/gem.rb +10 -10
- data/lib/yard/rubygems/backports/source_index.rb +365 -365
- data/lib/yard/rubygems/doc_manager.rb +90 -90
- data/lib/yard/rubygems/hook.rb +197 -197
- data/lib/yard/rubygems/specification.rb +50 -50
- data/lib/yard/serializers/base.rb +83 -83
- data/lib/yard/serializers/file_system_serializer.rb +123 -123
- data/lib/yard/serializers/process_serializer.rb +24 -24
- data/lib/yard/serializers/stdout_serializer.rb +34 -34
- data/lib/yard/serializers/yardoc_serializer.rb +152 -152
- data/lib/yard/server.rb +13 -13
- data/lib/yard/server/adapter.rb +100 -100
- data/lib/yard/server/commands/base.rb +209 -209
- data/lib/yard/server/commands/display_file_command.rb +29 -29
- data/lib/yard/server/commands/display_object_command.rb +65 -65
- data/lib/yard/server/commands/frames_command.rb +16 -16
- data/lib/yard/server/commands/library_command.rb +187 -187
- data/lib/yard/server/commands/library_index_command.rb +28 -28
- data/lib/yard/server/commands/list_command.rb +25 -25
- data/lib/yard/server/commands/root_request_command.rb +15 -15
- data/lib/yard/server/commands/search_command.rb +79 -79
- data/lib/yard/server/commands/static_file_command.rb +23 -23
- data/lib/yard/server/commands/static_file_helpers.rb +62 -62
- data/lib/yard/server/doc_server_helper.rb +91 -91
- data/lib/yard/server/doc_server_serializer.rb +39 -39
- data/lib/yard/server/library_version.rb +277 -277
- data/lib/yard/server/rack_adapter.rb +89 -89
- data/lib/yard/server/router.rb +187 -187
- data/lib/yard/server/static_caching.rb +46 -46
- data/lib/yard/server/templates/default/fulldoc/html/css/custom.css +127 -127
- data/lib/yard/server/templates/default/fulldoc/html/js/autocomplete.js +11 -11
- data/lib/yard/server/templates/default/layout/html/breadcrumb.erb +37 -37
- data/lib/yard/server/templates/default/layout/html/script_setup.erb +7 -7
- data/lib/yard/server/templates/default/layout/html/setup.rb +8 -8
- data/lib/yard/server/templates/default/method_details/html/permalink.erb +4 -4
- data/lib/yard/server/templates/default/method_details/html/setup.rb +5 -5
- data/lib/yard/server/templates/doc_server/library_list/html/headers.erb +8 -8
- data/lib/yard/server/templates/doc_server/library_list/html/library_list.erb +14 -14
- data/lib/yard/server/templates/doc_server/library_list/html/listing.erb +13 -13
- data/lib/yard/server/templates/doc_server/library_list/html/setup.rb +6 -6
- data/lib/yard/server/templates/doc_server/library_list/html/title.erb +2 -2
- data/lib/yard/server/templates/doc_server/processing/html/processing.erb +52 -52
- data/lib/yard/server/templates/doc_server/processing/html/setup.rb +4 -4
- data/lib/yard/server/templates/doc_server/search/html/search.erb +18 -18
- data/lib/yard/server/templates/doc_server/search/html/setup.rb +9 -9
- data/lib/yard/server/webrick_adapter.rb +45 -45
- data/lib/yard/tags/default_factory.rb +191 -191
- data/lib/yard/tags/default_tag.rb +13 -13
- data/lib/yard/tags/directives.rb +616 -616
- data/lib/yard/tags/library.rb +633 -633
- data/lib/yard/tags/option_tag.rb +13 -13
- data/lib/yard/tags/overload_tag.rb +71 -71
- data/lib/yard/tags/ref_tag.rb +8 -8
- data/lib/yard/tags/ref_tag_list.rb +28 -28
- data/lib/yard/tags/tag.rb +71 -71
- data/lib/yard/tags/tag_format_error.rb +7 -7
- data/lib/yard/tags/types_explainer.rb +162 -162
- data/lib/yard/templates/engine.rb +186 -186
- data/lib/yard/templates/erb_cache.rb +23 -23
- data/lib/yard/templates/helpers/base_helper.rb +215 -215
- data/lib/yard/templates/helpers/filter_helper.rb +27 -27
- data/lib/yard/templates/helpers/html_helper.rb +646 -646
- data/lib/yard/templates/helpers/html_syntax_highlight_helper.rb +78 -78
- data/lib/yard/templates/helpers/markup/rdoc_markdown.rb +23 -23
- data/lib/yard/templates/helpers/markup/rdoc_markup.rb +109 -109
- data/lib/yard/templates/helpers/markup_helper.rb +172 -172
- data/lib/yard/templates/helpers/method_helper.rb +75 -75
- data/lib/yard/templates/helpers/module_helper.rb +21 -21
- data/lib/yard/templates/helpers/text_helper.rb +112 -112
- data/lib/yard/templates/helpers/uml_helper.rb +47 -47
- data/lib/yard/templates/section.rb +105 -105
- data/lib/yard/templates/template.rb +418 -418
- data/lib/yard/templates/template_options.rb +92 -92
- data/lib/yard/verifier.rb +151 -151
- data/lib/yard/version.rb +6 -6
- data/spec/cli/command_parser_spec.rb +43 -43
- data/spec/cli/command_spec.rb +36 -36
- data/spec/cli/config_spec.rb +148 -148
- data/spec/cli/diff_spec.rb +254 -254
- data/spec/cli/display_spec.rb +30 -30
- data/spec/cli/gems_spec.rb +81 -81
- data/spec/cli/graph_spec.rb +18 -18
- data/spec/cli/help_spec.rb +22 -22
- data/spec/cli/i18n_spec.rb +107 -107
- data/spec/cli/list_spec.rb +8 -8
- data/spec/cli/markup_types_spec.rb +22 -22
- data/spec/cli/server_spec.rb +324 -324
- data/spec/cli/stats_spec.rb +96 -96
- data/spec/cli/yard_on_yard_spec.rb +38 -38
- data/spec/cli/yardoc_spec.rb +896 -862
- data/spec/cli/yri_spec.rb +101 -101
- data/spec/code_objects/base_spec.rb +470 -470
- data/spec/code_objects/class_object_spec.rb +226 -226
- data/spec/code_objects/code_object_list_spec.rb +36 -36
- data/spec/code_objects/constants_spec.rb +116 -116
- data/spec/code_objects/extra_file_object_spec.rb +160 -160
- data/spec/code_objects/macro_object_spec.rb +150 -150
- data/spec/code_objects/method_object_spec.rb +184 -184
- data/spec/code_objects/module_object_spec.rb +142 -142
- data/spec/code_objects/namespace_object_spec.rb +171 -171
- data/spec/code_objects/proxy_spec.rb +141 -141
- data/spec/code_objects/spec_helper.rb +3 -3
- data/spec/config_spec.rb +171 -171
- data/spec/core_ext/array_spec.rb +13 -13
- data/spec/core_ext/file_spec.rb +72 -72
- data/spec/core_ext/hash_spec.rb +14 -14
- data/spec/core_ext/insertion_spec.rb +37 -37
- data/spec/core_ext/module_spec.rb +9 -15
- data/spec/core_ext/string_spec.rb +42 -42
- data/spec/core_ext/symbol_hash_spec.rb +89 -89
- data/spec/docstring_parser_spec.rb +280 -280
- data/spec/docstring_spec.rb +373 -373
- data/spec/examples.txt +1883 -1875
- data/spec/handlers/alias_handler_spec.rb +82 -82
- data/spec/handlers/attribute_handler_spec.rb +96 -96
- data/spec/handlers/base_spec.rb +216 -216
- data/spec/handlers/c/alias_handler_spec.rb +34 -34
- data/spec/handlers/c/attribute_handler_spec.rb +41 -41
- data/spec/handlers/c/class_handler_spec.rb +78 -78
- data/spec/handlers/c/constant_handler_spec.rb +71 -71
- data/spec/handlers/c/init_handler_spec.rb +48 -48
- data/spec/handlers/c/method_handler_spec.rb +327 -325
- data/spec/handlers/c/mixin_handler_spec.rb +44 -44
- data/spec/handlers/c/module_handler_spec.rb +71 -71
- data/spec/handlers/c/override_comment_handler_spec.rb +47 -47
- data/spec/handlers/c/path_handler_spec.rb +36 -36
- data/spec/handlers/c/spec_helper.rb +23 -23
- data/spec/handlers/c/struct_handler_spec.rb +16 -16
- data/spec/handlers/class_condition_handler_spec.rb +87 -87
- data/spec/handlers/class_handler_spec.rb +247 -247
- data/spec/handlers/class_method_handler_shared_examples.rb +133 -133
- data/spec/handlers/class_variable_handler_spec.rb +12 -12
- data/spec/handlers/constant_handler_spec.rb +112 -112
- data/spec/handlers/decorator_handler_methods_spec.rb +393 -393
- data/spec/handlers/dsl_handler_spec.rb +219 -219
- data/spec/handlers/examples/alias_handler_001.rb.txt +45 -45
- data/spec/handlers/examples/attribute_handler_001.rb.txt +31 -31
- data/spec/handlers/examples/class_condition_handler_001.rb.txt +68 -68
- data/spec/handlers/examples/class_handler_001.rb.txt +120 -120
- data/spec/handlers/examples/class_variable_handler_001.rb.txt +9 -9
- data/spec/handlers/examples/constant_handler_001.rb.txt +35 -35
- data/spec/handlers/examples/dsl_handler_001.rb.txt +154 -154
- data/spec/handlers/examples/exception_handler_001.rb.txt +58 -58
- data/spec/handlers/examples/extend_handler_001.rb.txt +15 -15
- data/spec/handlers/examples/method_condition_handler_001.rb.txt +9 -9
- data/spec/handlers/examples/method_handler_001.rb.txt +128 -128
- data/spec/handlers/examples/mixin_handler_001.rb.txt +37 -37
- data/spec/handlers/examples/module_handler_001.rb.txt +29 -29
- data/spec/handlers/examples/private_constant_handler_001.rb.txt +8 -8
- data/spec/handlers/examples/process_handler_001.rb.txt +11 -11
- data/spec/handlers/examples/visibility_handler_001.rb.txt +35 -35
- data/spec/handlers/examples/yield_handler_001.rb.txt +54 -54
- data/spec/handlers/exception_handler_spec.rb +49 -49
- data/spec/handlers/extend_handler_spec.rb +24 -24
- data/spec/handlers/legacy_base_spec.rb +128 -128
- data/spec/handlers/method_condition_handler_spec.rb +15 -15
- data/spec/handlers/method_handler_spec.rb +190 -190
- data/spec/handlers/mixin_handler_spec.rb +56 -56
- data/spec/handlers/module_function_handler_spec.rb +106 -106
- data/spec/handlers/module_handler_spec.rb +35 -35
- data/spec/handlers/private_class_method_handler_spec.rb +11 -11
- data/spec/handlers/private_constant_handler_spec.rb +25 -25
- data/spec/handlers/processor_spec.rb +35 -35
- data/spec/handlers/public_class_method_handler_spec.rb +11 -11
- data/spec/handlers/ruby/base_spec.rb +95 -95
- data/spec/handlers/ruby/legacy/base_spec.rb +84 -84
- data/spec/handlers/spec_helper.rb +33 -33
- data/spec/handlers/visibility_handler_spec.rb +44 -44
- data/spec/handlers/yield_handler_spec.rb +52 -52
- data/spec/i18n/locale_spec.rb +81 -81
- data/spec/i18n/message_spec.rb +52 -52
- data/spec/i18n/messages_spec.rb +67 -67
- data/spec/i18n/pot_generator_spec.rb +295 -295
- data/spec/i18n/text_spec.rb +184 -184
- data/spec/logging_spec.rb +44 -44
- data/spec/options_spec.rb +171 -171
- data/spec/parser/base_spec.rb +24 -24
- data/spec/parser/c_parser_spec.rb +236 -236
- data/spec/parser/examples/array.c.txt +6267 -6267
- data/spec/parser/examples/example1.rb.txt +7 -7
- data/spec/parser/examples/extrafile.c.txt +8 -8
- data/spec/parser/examples/file.c.txt +28 -28
- data/spec/parser/examples/multifile.c.txt +22 -22
- data/spec/parser/examples/namespace.cpp.txt +68 -68
- data/spec/parser/examples/override.c.txt +424 -424
- data/spec/parser/examples/parse_in_order_001.rb.txt +2 -2
- data/spec/parser/examples/parse_in_order_002.rb.txt +1 -1
- data/spec/parser/examples/tag_handler_001.rb.txt +7 -7
- data/spec/parser/ruby/ast_node_spec.rb +33 -33
- data/spec/parser/ruby/legacy/statement_list_spec.rb +299 -299
- data/spec/parser/ruby/legacy/token_list_spec.rb +79 -79
- data/spec/parser/ruby/ruby_parser_spec.rb +508 -508
- data/spec/parser/ruby/token_resolver_spec.rb +165 -165
- data/spec/parser/source_parser_spec.rb +727 -727
- data/spec/parser/tag_parsing_spec.rb +17 -17
- data/spec/rake/yardoc_task_spec.rb +118 -118
- data/spec/registry_spec.rb +463 -463
- data/spec/registry_store_spec.rb +316 -316
- data/spec/rubygems/doc_manager_spec.rb +112 -112
- data/spec/serializers/data/serialized_yardoc/checksums +1 -1
- data/spec/serializers/file_system_serializer_spec.rb +145 -145
- data/spec/serializers/spec_helper.rb +2 -2
- data/spec/serializers/yardoc_serializer_spec.rb +78 -78
- data/spec/server/adapter_spec.rb +39 -39
- data/spec/server/commands/base_spec.rb +91 -91
- data/spec/server/commands/library_command_spec.rb +39 -39
- data/spec/server/doc_server_helper_spec.rb +72 -72
- data/spec/server/doc_server_serializer_spec.rb +60 -60
- data/spec/server/rack_adapter_spec.rb +21 -21
- data/spec/server/router_spec.rb +123 -123
- data/spec/server/spec_helper.rb +22 -22
- data/spec/server/static_caching_spec.rb +47 -47
- data/spec/server/webrick_servlet_spec.rb +20 -20
- data/spec/server_spec.rb +19 -19
- data/spec/spec_helper.rb +212 -212
- data/spec/tags/default_factory_spec.rb +168 -168
- data/spec/tags/default_tag_spec.rb +11 -11
- data/spec/tags/directives_spec.rb +463 -463
- data/spec/tags/library_spec.rb +48 -48
- data/spec/tags/overload_tag_spec.rb +53 -53
- data/spec/tags/ref_tag_list_spec.rb +53 -53
- data/spec/tags/types_explainer_spec.rb +203 -203
- data/spec/templates/class_spec.rb +45 -45
- data/spec/templates/constant_spec.rb +41 -41
- data/spec/templates/engine_spec.rb +131 -131
- data/spec/templates/examples/class001.html +308 -308
- data/spec/templates/examples/class001.txt +36 -36
- data/spec/templates/examples/class002.html +39 -39
- data/spec/templates/examples/constant001.txt +24 -24
- data/spec/templates/examples/constant002.txt +6 -6
- data/spec/templates/examples/constant003.txt +10 -10
- data/spec/templates/examples/method001.html +137 -137
- data/spec/templates/examples/method001.txt +35 -35
- data/spec/templates/examples/method002.html +91 -91
- data/spec/templates/examples/method002.txt +20 -20
- data/spec/templates/examples/method003.html +165 -165
- data/spec/templates/examples/method003.txt +45 -45
- data/spec/templates/examples/method004.html +48 -48
- data/spec/templates/examples/method004.txt +10 -10
- data/spec/templates/examples/method005.html +105 -105
- data/spec/templates/examples/method005.txt +33 -33
- data/spec/templates/examples/method006.html +107 -107
- data/spec/templates/examples/method006.txt +20 -20
- data/spec/templates/examples/module001.dot +33 -33
- data/spec/templates/examples/module001.html +833 -833
- data/spec/templates/examples/module001.txt +33 -33
- data/spec/templates/examples/module002.html +341 -341
- data/spec/templates/examples/module003.html +202 -202
- data/spec/templates/examples/module004.html +394 -394
- data/spec/templates/examples/module005.html +81 -81
- data/spec/templates/examples/tag001.txt +82 -82
- data/spec/templates/helpers/base_helper_spec.rb +171 -171
- data/spec/templates/helpers/html_helper_spec.rb +687 -668
- data/spec/templates/helpers/html_syntax_highlight_helper_spec.rb +65 -65
- data/spec/templates/helpers/markup/rdoc_markup_spec.rb +84 -84
- data/spec/templates/helpers/markup_helper_spec.rb +136 -136
- data/spec/templates/helpers/method_helper_spec.rb +107 -107
- data/spec/templates/helpers/module_helper_spec.rb +35 -35
- data/spec/templates/helpers/shared_signature_examples.rb +126 -126
- data/spec/templates/helpers/text_helper_spec.rb +65 -65
- data/spec/templates/method_spec.rb +118 -118
- data/spec/templates/module_spec.rb +203 -203
- data/spec/templates/onefile_spec.rb +66 -66
- data/spec/templates/section_spec.rb +144 -144
- data/spec/templates/spec_helper.rb +76 -76
- data/spec/templates/tag_spec.rb +52 -52
- data/spec/templates/template_spec.rb +410 -410
- data/spec/verifier_spec.rb +106 -106
- data/templates/default/class/dot/setup.rb +7 -7
- data/templates/default/class/dot/superklass.erb +2 -2
- data/templates/default/class/html/constructor_details.erb +8 -8
- data/templates/default/class/html/setup.rb +2 -2
- data/templates/default/class/html/subclasses.erb +4 -4
- data/templates/default/class/setup.rb +36 -36
- data/templates/default/class/text/setup.rb +12 -12
- data/templates/default/class/text/subclasses.erb +5 -5
- data/templates/default/constant/text/header.erb +11 -11
- data/templates/default/constant/text/setup.rb +4 -4
- data/templates/default/docstring/html/abstract.erb +4 -4
- data/templates/default/docstring/html/deprecated.erb +1 -1
- data/templates/default/docstring/html/index.erb +5 -5
- data/templates/default/docstring/html/note.erb +6 -6
- data/templates/default/docstring/html/private.erb +4 -4
- data/templates/default/docstring/html/text.erb +1 -1
- data/templates/default/docstring/html/todo.erb +6 -6
- data/templates/default/docstring/setup.rb +52 -52
- data/templates/default/docstring/text/abstract.erb +2 -2
- data/templates/default/docstring/text/deprecated.erb +2 -2
- data/templates/default/docstring/text/index.erb +2 -2
- data/templates/default/docstring/text/note.erb +3 -3
- data/templates/default/docstring/text/private.erb +2 -2
- data/templates/default/docstring/text/text.erb +1 -1
- data/templates/default/docstring/text/todo.erb +3 -3
- data/templates/default/fulldoc/html/css/full_list.css +58 -58
- data/templates/default/fulldoc/html/css/style.css +496 -496
- data/templates/default/fulldoc/html/frames.erb +17 -17
- data/templates/default/fulldoc/html/full_list.erb +37 -37
- data/templates/default/fulldoc/html/full_list_class.erb +2 -2
- data/templates/default/fulldoc/html/full_list_file.erb +7 -7
- data/templates/default/fulldoc/html/full_list_method.erb +10 -10
- data/templates/default/fulldoc/html/js/app.js +303 -292
- data/templates/default/fulldoc/html/js/full_list.js +216 -216
- data/templates/default/fulldoc/html/js/jquery.js +3 -3
- data/templates/default/fulldoc/html/setup.rb +241 -241
- data/templates/default/layout/dot/header.erb +5 -5
- data/templates/default/layout/dot/setup.rb +15 -15
- data/templates/default/layout/html/breadcrumb.erb +11 -11
- data/templates/default/layout/html/files.erb +11 -11
- data/templates/default/layout/html/footer.erb +5 -5
- data/templates/default/layout/html/headers.erb +15 -15
- data/templates/default/layout/html/index.erb +2 -2
- data/templates/default/layout/html/layout.erb +23 -23
- data/templates/default/layout/html/listing.erb +4 -4
- data/templates/default/layout/html/objects.erb +32 -32
- data/templates/default/layout/html/script_setup.erb +4 -4
- data/templates/default/layout/html/search.erb +12 -12
- data/templates/default/layout/html/setup.rb +89 -89
- data/templates/default/method/html/header.erb +16 -16
- data/templates/default/method/setup.rb +4 -4
- data/templates/default/method_details/html/header.erb +2 -2
- data/templates/default/method_details/html/method_signature.erb +24 -24
- data/templates/default/method_details/html/source.erb +9 -9
- data/templates/default/method_details/setup.rb +11 -11
- data/templates/default/method_details/text/header.erb +10 -10
- data/templates/default/method_details/text/method_signature.erb +12 -12
- data/templates/default/method_details/text/setup.rb +11 -11
- data/templates/default/module/dot/child.erb +1 -1
- data/templates/default/module/dot/dependencies.erb +2 -2
- data/templates/default/module/dot/header.erb +6 -6
- data/templates/default/module/dot/info.erb +13 -13
- data/templates/default/module/dot/setup.rb +15 -15
- data/templates/default/module/html/attribute_details.erb +10 -10
- data/templates/default/module/html/attribute_summary.erb +8 -8
- data/templates/default/module/html/box_info.erb +43 -43
- data/templates/default/module/html/children.erb +8 -8
- data/templates/default/module/html/constant_summary.erb +17 -17
- data/templates/default/module/html/defines.erb +2 -2
- data/templates/default/module/html/header.erb +5 -5
- data/templates/default/module/html/inherited_attributes.erb +14 -14
- data/templates/default/module/html/inherited_constants.erb +8 -8
- data/templates/default/module/html/inherited_methods.erb +18 -18
- data/templates/default/module/html/item_summary.erb +40 -40
- data/templates/default/module/html/method_details_list.erb +9 -9
- data/templates/default/module/html/method_summary.erb +13 -13
- data/templates/default/module/html/methodmissing.erb +12 -12
- data/templates/default/module/setup.rb +167 -167
- data/templates/default/module/text/children.erb +9 -9
- data/templates/default/module/text/class_meths_list.erb +7 -7
- data/templates/default/module/text/extends.erb +7 -7
- data/templates/default/module/text/header.erb +7 -7
- data/templates/default/module/text/includes.erb +7 -7
- data/templates/default/module/text/instance_meths_list.erb +7 -7
- data/templates/default/module/text/setup.rb +13 -13
- data/templates/default/onefile/html/files.erb +4 -4
- data/templates/default/onefile/html/headers.erb +6 -6
- data/templates/default/onefile/html/layout.erb +17 -17
- data/templates/default/onefile/html/readme.erb +2 -2
- data/templates/default/onefile/html/setup.rb +62 -62
- data/templates/default/root/dot/child.erb +2 -2
- data/templates/default/root/dot/setup.rb +6 -6
- data/templates/default/root/html/setup.rb +2 -2
- data/templates/default/tags/html/example.erb +10 -10
- data/templates/default/tags/html/index.erb +2 -2
- data/templates/default/tags/html/option.erb +24 -24
- data/templates/default/tags/html/overload.erb +13 -13
- data/templates/default/tags/html/see.erb +7 -7
- data/templates/default/tags/html/tag.erb +20 -20
- data/templates/default/tags/setup.rb +57 -57
- data/templates/default/tags/text/example.erb +12 -12
- data/templates/default/tags/text/index.erb +1 -1
- data/templates/default/tags/text/option.erb +20 -20
- data/templates/default/tags/text/overload.erb +19 -19
- data/templates/default/tags/text/see.erb +11 -11
- data/templates/default/tags/text/tag.erb +13 -13
- data/templates/guide/class/html/setup.rb +2 -2
- data/templates/guide/docstring/html/setup.rb +2 -2
- data/templates/guide/fulldoc/html/css/style.css +108 -108
- data/templates/guide/fulldoc/html/js/app.js +33 -33
- data/templates/guide/fulldoc/html/setup.rb +74 -74
- data/templates/guide/layout/html/layout.erb +81 -81
- data/templates/guide/layout/html/setup.rb +25 -25
- data/templates/guide/method/html/header.erb +17 -17
- data/templates/guide/method/html/setup.rb +22 -22
- data/templates/guide/module/html/header.erb +6 -6
- data/templates/guide/module/html/method_list.erb +4 -4
- data/templates/guide/module/html/setup.rb +27 -27
- data/templates/guide/onefile/html/files.erb +4 -4
- data/templates/guide/onefile/html/setup.rb +6 -6
- data/templates/guide/onefile/html/toc.erb +3 -3
- data/templates/guide/tags/html/setup.rb +9 -9
- data/yard.gemspec +43 -43
- metadata +4 -3
@@ -1,156 +1,156 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
module YARD
|
3
|
-
module Parser
|
4
|
-
module Ruby
|
5
|
-
# Supports {#each} enumeration over a source's tokens, yielding
|
6
|
-
# the token and a possible {CodeObjects::Base} associated with the
|
7
|
-
# constant or identifier token.
|
8
|
-
class TokenResolver
|
9
|
-
include Enumerable
|
10
|
-
|
11
|
-
# Creates a token resolver for given source.
|
12
|
-
#
|
13
|
-
# @param source [String] the source code to tokenize
|
14
|
-
# @param namespace [CodeObjects::Base] the object/namespace to resolve from
|
15
|
-
def initialize(source, namespace = Registry.root)
|
16
|
-
@tokens = RubyParser.parse(source, '(tokenize)').tokens
|
17
|
-
raise ParserSyntaxError if @tokens.empty? && !source.empty?
|
18
|
-
@default_namespace = namespace
|
19
|
-
end
|
20
|
-
|
21
|
-
# Iterates over each token, yielding the token and a possible code
|
22
|
-
# object that is associated with the token.
|
23
|
-
#
|
24
|
-
# @yieldparam token [Array(Symbol,String,Array(Integer,Integer))] the
|
25
|
-
# current token object being iterated
|
26
|
-
# @yieldparam object [CodeObjects::Base, nil] the fully qualified code
|
27
|
-
# object associated with the current token, or nil if there is no object
|
28
|
-
# for the yielded token.
|
29
|
-
# @example Yielding code objects
|
30
|
-
# r = TokenResolver.new("A::B::C")
|
31
|
-
# r.each do |tok, obj|
|
32
|
-
# if obj
|
33
|
-
# puts "#{tok[0]} -> #{obj.path.inspect}"
|
34
|
-
# else
|
35
|
-
# puts "No object: #{tok.inspect}"
|
36
|
-
# end
|
37
|
-
# end
|
38
|
-
#
|
39
|
-
# # Prints:
|
40
|
-
# # :const -> "A"
|
41
|
-
# # No object: [:op, "::"]
|
42
|
-
# # :const -> "A::B"
|
43
|
-
# # No object: [:op, "::"]
|
44
|
-
# # :const -> "A::B::C"
|
45
|
-
def each
|
46
|
-
@states = []
|
47
|
-
push_state
|
48
|
-
@tokens.each do |token|
|
49
|
-
yield_obj = false
|
50
|
-
|
51
|
-
if skip_group && [:const, :ident, :op, :period].include?(token[0])
|
52
|
-
yield token, nil
|
53
|
-
next
|
54
|
-
else
|
55
|
-
self.skip_group = false
|
56
|
-
end
|
57
|
-
|
58
|
-
case token[0]
|
59
|
-
when :const
|
60
|
-
lookup(token[0], token[1])
|
61
|
-
yield_obj = true
|
62
|
-
self.last_sep = nil
|
63
|
-
when :ident
|
64
|
-
lookup(token[0], token[1])
|
65
|
-
yield_obj = true
|
66
|
-
self.last_sep = nil
|
67
|
-
when :op, :period
|
68
|
-
self.last_sep = token[1]
|
69
|
-
unless CodeObjects.types_for_separator(token[1])
|
70
|
-
self.object = nil
|
71
|
-
self.last_sep = nil
|
72
|
-
end
|
73
|
-
when :lparen
|
74
|
-
push_state
|
75
|
-
when :rparen
|
76
|
-
pop_state
|
77
|
-
else
|
78
|
-
self.object = nil
|
79
|
-
end
|
80
|
-
|
81
|
-
yield token, (yield_obj ? object : nil)
|
82
|
-
|
83
|
-
if next_object
|
84
|
-
self.object = next_object
|
85
|
-
self.next_object = nil
|
86
|
-
end
|
87
|
-
self.skip_group = true if yield_obj && object.nil?
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def self.state_attr(*attrs)
|
92
|
-
attrs.each do |attr|
|
93
|
-
define_method(attr) { @states.last[attr.to_sym] }
|
94
|
-
define_method("#{attr}=") {|v| @states.last[attr.to_sym] = v }
|
95
|
-
protected attr, :"#{attr}="
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
private
|
100
|
-
|
101
|
-
def push_state
|
102
|
-
@states.push :object => nil, :skip_group => false, :last_sep => nil
|
103
|
-
end
|
104
|
-
|
105
|
-
def pop_state
|
106
|
-
@states.pop
|
107
|
-
end
|
108
|
-
|
109
|
-
state_attr :object, :next_object, :skip_group, :last_sep
|
110
|
-
|
111
|
-
def lookup(toktype, name)
|
112
|
-
types = object_resolved_types
|
113
|
-
return self.object = nil if types.empty?
|
114
|
-
|
115
|
-
if toktype == :const
|
116
|
-
types.any? do |type|
|
117
|
-
prefix = (type ? type.path : "") + last_sep.to_s
|
118
|
-
self.object = Registry.resolve(@default_namespace, "#{prefix}#{name}", true)
|
119
|
-
end
|
120
|
-
else # ident
|
121
|
-
types.any? do |type|
|
122
|
-
obj = Registry.resolve(type, name, true)
|
123
|
-
if obj.nil? && name == "new"
|
124
|
-
obj = Registry.resolve(object, "#initialize", true)
|
125
|
-
self.next_object = object if obj.nil?
|
126
|
-
end
|
127
|
-
self.object = obj
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
def object_resolved_types(obj = object)
|
133
|
-
return [obj] unless obj.is_a?(CodeObjects::MethodObject)
|
134
|
-
|
135
|
-
resolved_types = []
|
136
|
-
tags = obj.tags(:return)
|
137
|
-
tags += obj.tags(:overload).map {|o| o.tags(:return) }.flatten
|
138
|
-
tags.each do |tag|
|
139
|
-
next if tag.types.nil?
|
140
|
-
tag.types.each do |type|
|
141
|
-
type = type.sub(/<.+>/, '')
|
142
|
-
if type == "self"
|
143
|
-
resolved_types << obj.parent
|
144
|
-
else
|
145
|
-
type_obj = Registry.resolve(obj, type, true)
|
146
|
-
resolved_types << type_obj if type_obj
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
resolved_types
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module YARD
|
3
|
+
module Parser
|
4
|
+
module Ruby
|
5
|
+
# Supports {#each} enumeration over a source's tokens, yielding
|
6
|
+
# the token and a possible {CodeObjects::Base} associated with the
|
7
|
+
# constant or identifier token.
|
8
|
+
class TokenResolver
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
# Creates a token resolver for given source.
|
12
|
+
#
|
13
|
+
# @param source [String] the source code to tokenize
|
14
|
+
# @param namespace [CodeObjects::Base] the object/namespace to resolve from
|
15
|
+
def initialize(source, namespace = Registry.root)
|
16
|
+
@tokens = RubyParser.parse(source, '(tokenize)').tokens
|
17
|
+
raise ParserSyntaxError if @tokens.empty? && !source.empty?
|
18
|
+
@default_namespace = namespace
|
19
|
+
end
|
20
|
+
|
21
|
+
# Iterates over each token, yielding the token and a possible code
|
22
|
+
# object that is associated with the token.
|
23
|
+
#
|
24
|
+
# @yieldparam token [Array(Symbol,String,Array(Integer,Integer))] the
|
25
|
+
# current token object being iterated
|
26
|
+
# @yieldparam object [CodeObjects::Base, nil] the fully qualified code
|
27
|
+
# object associated with the current token, or nil if there is no object
|
28
|
+
# for the yielded token.
|
29
|
+
# @example Yielding code objects
|
30
|
+
# r = TokenResolver.new("A::B::C")
|
31
|
+
# r.each do |tok, obj|
|
32
|
+
# if obj
|
33
|
+
# puts "#{tok[0]} -> #{obj.path.inspect}"
|
34
|
+
# else
|
35
|
+
# puts "No object: #{tok.inspect}"
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# # Prints:
|
40
|
+
# # :const -> "A"
|
41
|
+
# # No object: [:op, "::"]
|
42
|
+
# # :const -> "A::B"
|
43
|
+
# # No object: [:op, "::"]
|
44
|
+
# # :const -> "A::B::C"
|
45
|
+
def each
|
46
|
+
@states = []
|
47
|
+
push_state
|
48
|
+
@tokens.each do |token|
|
49
|
+
yield_obj = false
|
50
|
+
|
51
|
+
if skip_group && [:const, :ident, :op, :period].include?(token[0])
|
52
|
+
yield token, nil
|
53
|
+
next
|
54
|
+
else
|
55
|
+
self.skip_group = false
|
56
|
+
end
|
57
|
+
|
58
|
+
case token[0]
|
59
|
+
when :const
|
60
|
+
lookup(token[0], token[1])
|
61
|
+
yield_obj = true
|
62
|
+
self.last_sep = nil
|
63
|
+
when :ident
|
64
|
+
lookup(token[0], token[1])
|
65
|
+
yield_obj = true
|
66
|
+
self.last_sep = nil
|
67
|
+
when :op, :period
|
68
|
+
self.last_sep = token[1]
|
69
|
+
unless CodeObjects.types_for_separator(token[1])
|
70
|
+
self.object = nil
|
71
|
+
self.last_sep = nil
|
72
|
+
end
|
73
|
+
when :lparen
|
74
|
+
push_state
|
75
|
+
when :rparen
|
76
|
+
pop_state
|
77
|
+
else
|
78
|
+
self.object = nil
|
79
|
+
end
|
80
|
+
|
81
|
+
yield token, (yield_obj ? object : nil)
|
82
|
+
|
83
|
+
if next_object
|
84
|
+
self.object = next_object
|
85
|
+
self.next_object = nil
|
86
|
+
end
|
87
|
+
self.skip_group = true if yield_obj && object.nil?
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.state_attr(*attrs)
|
92
|
+
attrs.each do |attr|
|
93
|
+
define_method(attr) { @states.last[attr.to_sym] }
|
94
|
+
define_method("#{attr}=") {|v| @states.last[attr.to_sym] = v }
|
95
|
+
protected attr, :"#{attr}="
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def push_state
|
102
|
+
@states.push :object => nil, :skip_group => false, :last_sep => nil
|
103
|
+
end
|
104
|
+
|
105
|
+
def pop_state
|
106
|
+
@states.pop
|
107
|
+
end
|
108
|
+
|
109
|
+
state_attr :object, :next_object, :skip_group, :last_sep
|
110
|
+
|
111
|
+
def lookup(toktype, name)
|
112
|
+
types = object_resolved_types
|
113
|
+
return self.object = nil if types.empty?
|
114
|
+
|
115
|
+
if toktype == :const
|
116
|
+
types.any? do |type|
|
117
|
+
prefix = (type ? type.path : "") + last_sep.to_s
|
118
|
+
self.object = Registry.resolve(@default_namespace, "#{prefix}#{name}", true)
|
119
|
+
end
|
120
|
+
else # ident
|
121
|
+
types.any? do |type|
|
122
|
+
obj = Registry.resolve(type, name, true)
|
123
|
+
if obj.nil? && name == "new"
|
124
|
+
obj = Registry.resolve(object, "#initialize", true)
|
125
|
+
self.next_object = object if obj.nil?
|
126
|
+
end
|
127
|
+
self.object = obj
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def object_resolved_types(obj = object)
|
133
|
+
return [obj] unless obj.is_a?(CodeObjects::MethodObject)
|
134
|
+
|
135
|
+
resolved_types = []
|
136
|
+
tags = obj.tags(:return)
|
137
|
+
tags += obj.tags(:overload).map {|o| o.tags(:return) }.flatten
|
138
|
+
tags.each do |tag|
|
139
|
+
next if tag.types.nil?
|
140
|
+
tag.types.each do |type|
|
141
|
+
type = type.sub(/<.+>/, '')
|
142
|
+
if type == "self"
|
143
|
+
resolved_types << obj.parent
|
144
|
+
else
|
145
|
+
type_obj = Registry.resolve(obj, type, true)
|
146
|
+
resolved_types << type_obj if type_obj
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
resolved_types
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -1,526 +1,526 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'stringio'
|
3
|
-
require 'ostruct'
|
4
|
-
|
5
|
-
module YARD
|
6
|
-
module Parser
|
7
|
-
# Raised when an object is recognized but cannot be documented. This
|
8
|
-
# generally occurs when the Ruby syntax used to declare an object is
|
9
|
-
# too dynamic in nature.
|
10
|
-
class UndocumentableError < RuntimeError; end
|
11
|
-
|
12
|
-
# Raised when the parser sees a Ruby syntax error
|
13
|
-
class ParserSyntaxError < UndocumentableError; end
|
14
|
-
|
15
|
-
# Responsible for parsing a list of files in order. The
|
16
|
-
# {#parse} method of this class can be called from the
|
17
|
-
# {SourceParser#globals} globals state list to re-enter
|
18
|
-
# parsing for the remainder of files in the list recursively.
|
19
|
-
#
|
20
|
-
# @see Processor#parse_remaining_files
|
21
|
-
class OrderedParser
|
22
|
-
# @return [Array<String>] the list of remaining files to parse
|
23
|
-
attr_accessor :files
|
24
|
-
|
25
|
-
# Creates a new OrderedParser with the global state and a list
|
26
|
-
# of files to parse.
|
27
|
-
#
|
28
|
-
# @note OrderedParser sets itself as the +ordered_parser+ key on
|
29
|
-
# global_state for later use in {Handlers::Processor}.
|
30
|
-
# @param [OpenStruct] global_state a structure containing all global
|
31
|
-
# state during parsing
|
32
|
-
# @param [Array<String>] files the list of files to parse
|
33
|
-
def initialize(global_state, files)
|
34
|
-
@global_state = global_state
|
35
|
-
@files = files.dup
|
36
|
-
@global_state.ordered_parser = self
|
37
|
-
end
|
38
|
-
|
39
|
-
# Parses the remainder of the {#files} list.
|
40
|
-
#
|
41
|
-
# @see Processor#parse_remaining_files
|
42
|
-
def parse
|
43
|
-
until files.empty?
|
44
|
-
file = files.shift
|
45
|
-
log.capture("Parsing #{file}") do
|
46
|
-
SourceParser.new(SourceParser.parser_type, @global_state).parse(file)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# Responsible for parsing a source file into the namespace. Parsing
|
53
|
-
# also invokes handlers to process the parsed statements and generate
|
54
|
-
# any code objects that may be recognized.
|
55
|
-
#
|
56
|
-
# == Custom Parsers
|
57
|
-
# SourceParser allows custom parsers to be registered and called when
|
58
|
-
# a certain filetype is recognized. To register a parser and hook it
|
59
|
-
# up to a set of file extensions, call {register_parser_type}
|
60
|
-
#
|
61
|
-
# @see register_parser_type
|
62
|
-
# @see Handlers::Base
|
63
|
-
# @see CodeObjects::Base
|
64
|
-
class SourceParser
|
65
|
-
SHEBANG_LINE = /\A\s*#!\S+/
|
66
|
-
ENCODING_LINE = %r{\A(?:\s*#*!.*\r?\n)?\s*(?:#+|/\*+|//+).*coding\s*[:=]{1,2}\s*([a-z\d_\-]+)}i
|
67
|
-
FROZEN_STRING_LINE = /frozen(-|_)string(-|_)literal: true/i
|
68
|
-
|
69
|
-
# The default glob of files to be parsed.
|
70
|
-
# @since 0.9.0
|
71
|
-
DEFAULT_PATH_GLOB = ["{lib,app}/**/*.rb", "ext/**/*.{c,cc,cxx,cpp,rb}"]
|
72
|
-
|
73
|
-
# Byte order marks for various encodings
|
74
|
-
# @since 0.7.0
|
75
|
-
ENCODING_BYTE_ORDER_MARKS = {
|
76
|
-
'utf-8' => String.new("\xEF\xBB\xBF"),
|
77
|
-
# Not yet supported
|
78
|
-
# 'utf-16be' => "\xFE\xFF",
|
79
|
-
# 'utf-16le' => "\xFF\xFE",
|
80
|
-
# 'utf-32be' => "\x00\x00\xFF\xFE",
|
81
|
-
# 'utf-32le' => "\xFF\xFE",
|
82
|
-
}
|
83
|
-
|
84
|
-
class << self
|
85
|
-
# @return [Symbol] the default parser type (defaults to :ruby)
|
86
|
-
attr_reader :parser_type
|
87
|
-
|
88
|
-
def parser_type=(value)
|
89
|
-
@parser_type = validated_parser_type(value)
|
90
|
-
end
|
91
|
-
|
92
|
-
# Parses a path or set of paths
|
93
|
-
#
|
94
|
-
# @param [String, Array<String>] paths a path, glob, or list of paths to
|
95
|
-
# parse
|
96
|
-
# @param [Array<String, Regexp>] excluded a list of excluded path matchers
|
97
|
-
# @param [Fixnum] level the logger level to use during parsing. See
|
98
|
-
# {YARD::Logger}
|
99
|
-
# @return [void]
|
100
|
-
def parse(paths = DEFAULT_PATH_GLOB, excluded = [], level = log.level)
|
101
|
-
log.debug("Parsing #{paths.inspect} with `#{parser_type}` parser")
|
102
|
-
excluded = excluded.map do |path|
|
103
|
-
case path
|
104
|
-
when Regexp; path
|
105
|
-
else Regexp.new(path.to_s, Regexp::IGNORECASE)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
files = [paths].flatten.
|
109
|
-
map {|p| File.directory?(p) ? "#{p}/**/*.{rb,c,cc,cxx,cpp}" : p }.
|
110
|
-
map {|p| p.include?("*") ? Dir[p].sort_by {|d| [d.length, d] } : p }.flatten.
|
111
|
-
reject {|p| !File.file?(p) || excluded.any? {|re| p =~ re } }
|
112
|
-
|
113
|
-
log.enter_level(level) do
|
114
|
-
parse_in_order(*files.uniq)
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
# Parses a string +content+
|
119
|
-
#
|
120
|
-
# @param [String] content the block of code to parse
|
121
|
-
# @param [Symbol] ptype the parser type to use. See {parser_type}.
|
122
|
-
# @return the parser object that was used to parse +content+
|
123
|
-
def parse_string(content, ptype = parser_type)
|
124
|
-
new(ptype).parse(StringIO.new(content))
|
125
|
-
end
|
126
|
-
|
127
|
-
# Tokenizes but does not parse the block of code
|
128
|
-
#
|
129
|
-
# @param [String] content the block of code to tokenize
|
130
|
-
# @param [Symbol] ptype the parser type to use. See {parser_type}.
|
131
|
-
# @return [Array] a list of tokens
|
132
|
-
def tokenize(content, ptype = parser_type)
|
133
|
-
new(ptype).tokenize(content)
|
134
|
-
end
|
135
|
-
|
136
|
-
# Registers a new parser type.
|
137
|
-
#
|
138
|
-
# @example Registering a parser for "java" files
|
139
|
-
# SourceParser.register_parser_type :java, JavaParser, 'java'
|
140
|
-
# @param [Symbol] type a symbolic name for the parser type
|
141
|
-
# @param [Base] parser_klass a class that implements parsing and tokenization
|
142
|
-
# @param [Array<String>, String, Regexp] extensions a list of extensions or a
|
143
|
-
# regex to match against the file extension
|
144
|
-
# @return [void]
|
145
|
-
# @see Parser::Base
|
146
|
-
def register_parser_type(type, parser_klass, extensions = nil)
|
147
|
-
unless Base > parser_klass
|
148
|
-
raise ArgumentError, "expecting parser_klass to be a subclass of YARD::Parser::Base"
|
149
|
-
end
|
150
|
-
parser_type_extensions[type.to_sym] = extensions if extensions
|
151
|
-
parser_types[type.to_sym] = parser_klass
|
152
|
-
end
|
153
|
-
|
154
|
-
# @return [Hash{Symbol=>Object}] a list of registered parser types
|
155
|
-
# @private
|
156
|
-
# @since 0.5.6
|
157
|
-
def parser_types; @@parser_types ||= {} end
|
158
|
-
def parser_types=(value) @@parser_types = value end
|
159
|
-
|
160
|
-
# @return [Hash] a list of registered parser type extensions
|
161
|
-
# @private
|
162
|
-
# @since 0.5.6
|
163
|
-
def parser_type_extensions; @@parser_type_extensions ||= {} end
|
164
|
-
def parser_type_extensions=(value) @@parser_type_extensions = value end
|
165
|
-
|
166
|
-
# Finds a parser type that is registered for the extension. If no
|
167
|
-
# type is found, the default Ruby type is returned.
|
168
|
-
#
|
169
|
-
# @return [Symbol] the parser type to be used for the extension
|
170
|
-
# @since 0.5.6
|
171
|
-
def parser_type_for_extension(extension)
|
172
|
-
type = parser_type_extensions.find do |_t, exts|
|
173
|
-
[exts].flatten.any? {|ext| ext === extension }
|
174
|
-
end
|
175
|
-
validated_parser_type(type ? type.first : :ruby)
|
176
|
-
end
|
177
|
-
|
178
|
-
# Returns the validated parser type. Basically, enforces that :ruby
|
179
|
-
# type is never set if the Ripper library is not available
|
180
|
-
#
|
181
|
-
# @param [Symbol] type the parser type to set
|
182
|
-
# @return [Symbol] the validated parser type
|
183
|
-
# @private
|
184
|
-
def validated_parser_type(type)
|
185
|
-
!defined?(::Ripper) && type == :ruby ? :ruby18 : type
|
186
|
-
end
|
187
|
-
|
188
|
-
# @group Parser Callbacks
|
189
|
-
|
190
|
-
# Registers a callback to be called before a list of files is parsed
|
191
|
-
# via {parse}. The block passed to this method will be called on
|
192
|
-
# subsequent parse calls.
|
193
|
-
#
|
194
|
-
# @example Installing a simple callback
|
195
|
-
# SourceParser.before_parse_list do |files, globals|
|
196
|
-
# puts "Starting to parse..."
|
197
|
-
# end
|
198
|
-
# YARD.parse('lib/**/*.rb')
|
199
|
-
# # prints "Starting to parse..."
|
200
|
-
#
|
201
|
-
# @example Setting global state
|
202
|
-
# SourceParser.before_parse_list do |files, globals|
|
203
|
-
# globals.method_count = 0
|
204
|
-
# end
|
205
|
-
# SourceParser.after_parse_list do |files, globals|
|
206
|
-
# puts "Found #{globals.method_count} methods"
|
207
|
-
# end
|
208
|
-
# class MyCountHandler < Handlers::Ruby::Base
|
209
|
-
# handles :def, :defs
|
210
|
-
# process { globals.method_count += 1 }
|
211
|
-
# end
|
212
|
-
# YARD.parse
|
213
|
-
# # Prints: "Found 37 methods"
|
214
|
-
#
|
215
|
-
# @example Using a global callback to cancel parsing
|
216
|
-
# SourceParser.before_parse_list do |files, globals|
|
217
|
-
# return false if files.include?('foo.rb')
|
218
|
-
# end
|
219
|
-
#
|
220
|
-
# YARD.parse(['foo.rb', 'bar.rb']) # callback cancels this method
|
221
|
-
# YARD.parse('bar.rb') # parses normally
|
222
|
-
#
|
223
|
-
# @yield [files, globals] the yielded block is called once before
|
224
|
-
# parsing all files
|
225
|
-
# @yieldparam [Array<String>] files the list of files that will be parsed.
|
226
|
-
# @yieldparam [OpenStruct] globals a global structure to store arbitrary
|
227
|
-
# state for post processing (see {Handlers::Processor#globals})
|
228
|
-
# @yieldreturn [Boolean] if the block returns +false+, parsing is
|
229
|
-
# cancelled.
|
230
|
-
# @return [Proc] the yielded block
|
231
|
-
# @see after_parse_list
|
232
|
-
# @see before_parse_file
|
233
|
-
# @since 0.7.0
|
234
|
-
def before_parse_list(&block)
|
235
|
-
before_parse_list_callbacks << block
|
236
|
-
end
|
237
|
-
|
238
|
-
# Registers a callback to be called after a list of files is parsed
|
239
|
-
# via {parse}. The block passed to this method will be called on
|
240
|
-
# subsequent parse calls.
|
241
|
-
#
|
242
|
-
# @example Printing results after parsing occurs
|
243
|
-
# SourceParser.after_parse_list do
|
244
|
-
# puts "Finished parsing!"
|
245
|
-
# end
|
246
|
-
# YARD.parse
|
247
|
-
# # Prints "Finished parsing!" after parsing files
|
248
|
-
# @yield [files, globals] the yielded block is called once before
|
249
|
-
# parsing all files
|
250
|
-
# @yieldparam [Array<String>] files the list of files that will be parsed.
|
251
|
-
# @yieldparam [OpenStruct] globals a global structure to store arbitrary
|
252
|
-
# state for post processing (see {Handlers::Processor#globals})
|
253
|
-
# @yieldreturn [void] the return value for the block is ignored.
|
254
|
-
# @return [Proc] the yielded block
|
255
|
-
# @see before_parse_list
|
256
|
-
# @see before_parse_file
|
257
|
-
# @since 0.7.0
|
258
|
-
def after_parse_list(&block)
|
259
|
-
after_parse_list_callbacks << block
|
260
|
-
end
|
261
|
-
|
262
|
-
# Registers a callback to be called before an individual file is parsed.
|
263
|
-
# The block passed to this method will be called on subsequent parse
|
264
|
-
# calls.
|
265
|
-
#
|
266
|
-
# To register a callback that is called before the entire list of files
|
267
|
-
# is processed, see {before_parse_list}.
|
268
|
-
#
|
269
|
-
# @example Installing a simple callback
|
270
|
-
# SourceParser.before_parse_file do |parser|
|
271
|
-
# puts "I'm parsing #{parser.file}"
|
272
|
-
# end
|
273
|
-
# YARD.parse('lib/**/*.rb')
|
274
|
-
# # prints:
|
275
|
-
# "I'm parsing lib/foo.rb"
|
276
|
-
# "I'm parsing lib/foo_bar.rb"
|
277
|
-
# "I'm parsing lib/last_file.rb"
|
278
|
-
#
|
279
|
-
# @example Cancel parsing of any test_*.rb files
|
280
|
-
# SourceParser.before_parse_file do |parser|
|
281
|
-
# return false if parser.file =~ /^test_.+\.rb$/
|
282
|
-
# end
|
283
|
-
#
|
284
|
-
# @yield [parser] the yielded block is called once before each
|
285
|
-
# file that is parsed. This might happen many times for a single
|
286
|
-
# codebase.
|
287
|
-
# @yieldparam [SourceParser] parser the parser object that will {#parse}
|
288
|
-
# the file.
|
289
|
-
# @yieldreturn [Boolean] if the block returns +false+, parsing for
|
290
|
-
# the file is cancelled.
|
291
|
-
# @return [Proc] the yielded block
|
292
|
-
# @see after_parse_file
|
293
|
-
# @see before_parse_list
|
294
|
-
# @since 0.7.0
|
295
|
-
def before_parse_file(&block)
|
296
|
-
before_parse_file_callbacks << block
|
297
|
-
end
|
298
|
-
|
299
|
-
# Registers a callback to be called after an individual file is parsed.
|
300
|
-
# The block passed to this method will be called on subsequent parse
|
301
|
-
# calls.
|
302
|
-
#
|
303
|
-
# To register a callback that is called after the entire list of files
|
304
|
-
# is processed, see {after_parse_list}.
|
305
|
-
#
|
306
|
-
# @example Printing the length of each file after it is parsed
|
307
|
-
# SourceParser.after_parse_file do |parser|
|
308
|
-
# puts "#{parser.file} is #{parser.contents.size} characters"
|
309
|
-
# end
|
310
|
-
# YARD.parse('lib/**/*.rb')
|
311
|
-
# # prints:
|
312
|
-
# "lib/foo.rb is 1240 characters"
|
313
|
-
# "lib/foo_bar.rb is 248 characters"
|
314
|
-
#
|
315
|
-
# @yield [parser] the yielded block is called once after each file
|
316
|
-
# that is parsed. This might happen many times for a single codebase.
|
317
|
-
# @yieldparam [SourceParser] parser the parser object that parsed
|
318
|
-
# the file.
|
319
|
-
# @yieldreturn [void] the return value for the block is ignored.
|
320
|
-
# @return [Proc] the yielded block
|
321
|
-
# @see before_parse_file
|
322
|
-
# @see after_parse_list
|
323
|
-
# @since 0.7.0
|
324
|
-
def after_parse_file(&block)
|
325
|
-
after_parse_file_callbacks << block
|
326
|
-
end
|
327
|
-
|
328
|
-
# @return [Array<Proc>] the list of callbacks to be called before
|
329
|
-
# parsing a list of files. Should only be used for testing.
|
330
|
-
# @since 0.7.0
|
331
|
-
def before_parse_list_callbacks
|
332
|
-
@before_parse_list_callbacks ||= []
|
333
|
-
end
|
334
|
-
|
335
|
-
# @return [Array<Proc>] the list of callbacks to be called after
|
336
|
-
# parsing a list of files. Should only be used for testing.
|
337
|
-
# @since 0.7.0
|
338
|
-
def after_parse_list_callbacks
|
339
|
-
@after_parse_list_callbacks ||= []
|
340
|
-
end
|
341
|
-
|
342
|
-
# @return [Array<Proc>] the list of callbacks to be called before
|
343
|
-
# parsing a file. Should only be used for testing.
|
344
|
-
# @since 0.7.0
|
345
|
-
def before_parse_file_callbacks
|
346
|
-
@before_parse_file_callbacks ||= []
|
347
|
-
end
|
348
|
-
|
349
|
-
# @return [Array<Proc>] the list of callbacks to be called after
|
350
|
-
# parsing a file. Should only be used for testing.
|
351
|
-
# @since 0.7.0
|
352
|
-
def after_parse_file_callbacks
|
353
|
-
@after_parse_file_callbacks ||= []
|
354
|
-
end
|
355
|
-
|
356
|
-
# @endgroup
|
357
|
-
|
358
|
-
private
|
359
|
-
|
360
|
-
# Parses a list of files in a queue.
|
361
|
-
#
|
362
|
-
# @param [Array<String>] files a list of files to queue for parsing
|
363
|
-
# @return [void]
|
364
|
-
def parse_in_order(*files)
|
365
|
-
global_state = OpenStruct.new
|
366
|
-
|
367
|
-
return if before_parse_list_callbacks.any? do |cb|
|
368
|
-
cb.call(files, global_state) == false
|
369
|
-
end
|
370
|
-
|
371
|
-
OrderedParser.new(global_state, files).parse
|
372
|
-
|
373
|
-
after_parse_list_callbacks.each do |cb|
|
374
|
-
cb.call(files, global_state)
|
375
|
-
end
|
376
|
-
end
|
377
|
-
end
|
378
|
-
|
379
|
-
register_parser_type :ruby, Ruby::RubyParser
|
380
|
-
register_parser_type :ruby18, Ruby::Legacy::RubyParser
|
381
|
-
register_parser_type :c, C::CParser, ['c', 'cc', 'cxx', 'cpp']
|
382
|
-
|
383
|
-
self.parser_type = :ruby
|
384
|
-
|
385
|
-
# @return [String] the filename being parsed by the parser.
|
386
|
-
attr_accessor :file
|
387
|
-
|
388
|
-
# @return [Symbol] the parser type associated with the parser instance.
|
389
|
-
# This should be set by the {#initialize constructor}.
|
390
|
-
attr_reader :parser_type
|
391
|
-
|
392
|
-
# @return [OpenStruct] an open struct containing arbitrary global state
|
393
|
-
# shared between files and handlers.
|
394
|
-
# @since 0.7.0
|
395
|
-
attr_reader :globals
|
396
|
-
|
397
|
-
# @return [String] the contents of the file to be parsed
|
398
|
-
# @since 0.7.0
|
399
|
-
attr_reader :contents
|
400
|
-
|
401
|
-
# @overload initialize(parser_type = SourceParser.parser_type, globals = nil)
|
402
|
-
# Creates a new parser object for code parsing with a specific parser type.
|
403
|
-
#
|
404
|
-
# @param [Symbol] parser_type the parser type to use
|
405
|
-
# @param [OpenStruct] globals global state to be re-used across separate source files
|
406
|
-
def initialize(parser_type = SourceParser.parser_type, globals1 = nil, globals2 = nil)
|
407
|
-
globals = [true, false].include?(globals1) ? globals2 : globals1
|
408
|
-
@file = '(stdin)'
|
409
|
-
@globals = globals || OpenStruct.new
|
410
|
-
self.parser_type = parser_type
|
411
|
-
end
|
412
|
-
|
413
|
-
# The main parser method. This should not be called directly. Instead,
|
414
|
-
# use the class methods {parse} and {parse_string}.
|
415
|
-
#
|
416
|
-
# @param [String, #read, Object] content the source file to parse
|
417
|
-
# @return [Object, nil] the parser object used to parse the source
|
418
|
-
def parse(content = __FILE__)
|
419
|
-
case content
|
420
|
-
when String
|
421
|
-
@file = File.cleanpath(content)
|
422
|
-
content = convert_encoding(String.new(File.read_binary(file)))
|
423
|
-
checksum = Registry.checksum_for(content)
|
424
|
-
return if Registry.checksums[file] == checksum
|
425
|
-
|
426
|
-
if Registry.checksums.key?(file)
|
427
|
-
log.info "File '#{file}' was modified, re-processing..."
|
428
|
-
end
|
429
|
-
Registry.checksums[@file] = checksum
|
430
|
-
self.parser_type = parser_type_for_filename(file)
|
431
|
-
else
|
432
|
-
content = content.read if content.respond_to? :read
|
433
|
-
end
|
434
|
-
|
435
|
-
@contents = content
|
436
|
-
@parser = parser_class.new(content, file)
|
437
|
-
|
438
|
-
self.class.before_parse_file_callbacks.each do |cb|
|
439
|
-
return @parser if cb.call(self) == false
|
440
|
-
end
|
441
|
-
|
442
|
-
@parser.parse
|
443
|
-
post_process
|
444
|
-
|
445
|
-
self.class.after_parse_file_callbacks.each do |cb|
|
446
|
-
cb.call(self)
|
447
|
-
end
|
448
|
-
|
449
|
-
@parser
|
450
|
-
rescue ArgumentError, NotImplementedError => e
|
451
|
-
log.warn("Cannot parse `#{file}': #{e.message}")
|
452
|
-
log.backtrace(e, :warn)
|
453
|
-
rescue ParserSyntaxError => e
|
454
|
-
log.warn(e.message.capitalize)
|
455
|
-
log.backtrace(e, :warn)
|
456
|
-
end
|
457
|
-
|
458
|
-
# Tokenizes but does not parse the block of code using the current {#parser_type}
|
459
|
-
#
|
460
|
-
# @param [String] content the block of code to tokenize
|
461
|
-
# @return [Array] a list of tokens
|
462
|
-
def tokenize(content)
|
463
|
-
@parser = parser_class.new(content, file)
|
464
|
-
@parser.tokenize
|
465
|
-
end
|
466
|
-
|
467
|
-
private
|
468
|
-
|
469
|
-
# Searches for encoding line and forces encoding
|
470
|
-
# @since 0.5.3
|
471
|
-
def convert_encoding(content)
|
472
|
-
return content unless content.respond_to?(:force_encoding)
|
473
|
-
if content =~ ENCODING_LINE
|
474
|
-
content.force_encoding($1)
|
475
|
-
else
|
476
|
-
content.force_encoding('binary')
|
477
|
-
ENCODING_BYTE_ORDER_MARKS.each do |encoding, bom|
|
478
|
-
bom.force_encoding('binary')
|
479
|
-
if content[0, bom.size] == bom
|
480
|
-
content.force_encoding(encoding)
|
481
|
-
return content
|
482
|
-
end
|
483
|
-
end
|
484
|
-
content.force_encoding('utf-8') # UTF-8 is default encoding
|
485
|
-
content
|
486
|
-
end
|
487
|
-
end
|
488
|
-
|
489
|
-
# Runs a {Handlers::Processor} object to post process the parsed statements.
|
490
|
-
# @return [void]
|
491
|
-
def post_process
|
492
|
-
return unless @parser.respond_to?(:enumerator)
|
493
|
-
|
494
|
-
enumerator = @parser.enumerator
|
495
|
-
if enumerator
|
496
|
-
post = Handlers::Processor.new(self)
|
497
|
-
post.process(enumerator)
|
498
|
-
end
|
499
|
-
end
|
500
|
-
|
501
|
-
def parser_type=(value)
|
502
|
-
@parser_type = self.class.validated_parser_type(value)
|
503
|
-
end
|
504
|
-
|
505
|
-
# Guesses the parser type to use depending on the file extension.
|
506
|
-
#
|
507
|
-
# @param [String] filename the filename to use to guess the parser type
|
508
|
-
# @return [Symbol] a parser type that matches the filename
|
509
|
-
def parser_type_for_filename(filename)
|
510
|
-
ext = (File.extname(filename)[1..-1] || "").downcase
|
511
|
-
type = self.class.parser_type_for_extension(ext)
|
512
|
-
parser_type == :ruby18 && type == :ruby ? :ruby18 : type
|
513
|
-
end
|
514
|
-
|
515
|
-
# @since 0.5.6
|
516
|
-
def parser_class
|
517
|
-
klass = self.class.parser_types[parser_type]
|
518
|
-
unless klass
|
519
|
-
raise ArgumentError, "invalid parser type '#{parser_type}' or unrecognized file", caller[1..-1]
|
520
|
-
end
|
521
|
-
|
522
|
-
klass
|
523
|
-
end
|
524
|
-
end
|
525
|
-
end
|
526
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'stringio'
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
module YARD
|
6
|
+
module Parser
|
7
|
+
# Raised when an object is recognized but cannot be documented. This
|
8
|
+
# generally occurs when the Ruby syntax used to declare an object is
|
9
|
+
# too dynamic in nature.
|
10
|
+
class UndocumentableError < RuntimeError; end
|
11
|
+
|
12
|
+
# Raised when the parser sees a Ruby syntax error
|
13
|
+
class ParserSyntaxError < UndocumentableError; end
|
14
|
+
|
15
|
+
# Responsible for parsing a list of files in order. The
|
16
|
+
# {#parse} method of this class can be called from the
|
17
|
+
# {SourceParser#globals} globals state list to re-enter
|
18
|
+
# parsing for the remainder of files in the list recursively.
|
19
|
+
#
|
20
|
+
# @see Processor#parse_remaining_files
|
21
|
+
class OrderedParser
|
22
|
+
# @return [Array<String>] the list of remaining files to parse
|
23
|
+
attr_accessor :files
|
24
|
+
|
25
|
+
# Creates a new OrderedParser with the global state and a list
|
26
|
+
# of files to parse.
|
27
|
+
#
|
28
|
+
# @note OrderedParser sets itself as the +ordered_parser+ key on
|
29
|
+
# global_state for later use in {Handlers::Processor}.
|
30
|
+
# @param [OpenStruct] global_state a structure containing all global
|
31
|
+
# state during parsing
|
32
|
+
# @param [Array<String>] files the list of files to parse
|
33
|
+
def initialize(global_state, files)
|
34
|
+
@global_state = global_state
|
35
|
+
@files = files.dup
|
36
|
+
@global_state.ordered_parser = self
|
37
|
+
end
|
38
|
+
|
39
|
+
# Parses the remainder of the {#files} list.
|
40
|
+
#
|
41
|
+
# @see Processor#parse_remaining_files
|
42
|
+
def parse
|
43
|
+
until files.empty?
|
44
|
+
file = files.shift
|
45
|
+
log.capture("Parsing #{file}") do
|
46
|
+
SourceParser.new(SourceParser.parser_type, @global_state).parse(file)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Responsible for parsing a source file into the namespace. Parsing
|
53
|
+
# also invokes handlers to process the parsed statements and generate
|
54
|
+
# any code objects that may be recognized.
|
55
|
+
#
|
56
|
+
# == Custom Parsers
|
57
|
+
# SourceParser allows custom parsers to be registered and called when
|
58
|
+
# a certain filetype is recognized. To register a parser and hook it
|
59
|
+
# up to a set of file extensions, call {register_parser_type}
|
60
|
+
#
|
61
|
+
# @see register_parser_type
|
62
|
+
# @see Handlers::Base
|
63
|
+
# @see CodeObjects::Base
|
64
|
+
class SourceParser
|
65
|
+
SHEBANG_LINE = /\A\s*#!\S+/
|
66
|
+
ENCODING_LINE = %r{\A(?:\s*#*!.*\r?\n)?\s*(?:#+|/\*+|//+).*coding\s*[:=]{1,2}\s*([a-z\d_\-]+)}i
|
67
|
+
FROZEN_STRING_LINE = /frozen(-|_)string(-|_)literal: true/i
|
68
|
+
|
69
|
+
# The default glob of files to be parsed.
|
70
|
+
# @since 0.9.0
|
71
|
+
DEFAULT_PATH_GLOB = ["{lib,app}/**/*.rb", "ext/**/*.{c,cc,cxx,cpp,rb}"]
|
72
|
+
|
73
|
+
# Byte order marks for various encodings
|
74
|
+
# @since 0.7.0
|
75
|
+
ENCODING_BYTE_ORDER_MARKS = {
|
76
|
+
'utf-8' => String.new("\xEF\xBB\xBF"),
|
77
|
+
# Not yet supported
|
78
|
+
# 'utf-16be' => "\xFE\xFF",
|
79
|
+
# 'utf-16le' => "\xFF\xFE",
|
80
|
+
# 'utf-32be' => "\x00\x00\xFF\xFE",
|
81
|
+
# 'utf-32le' => "\xFF\xFE",
|
82
|
+
}
|
83
|
+
|
84
|
+
class << self
|
85
|
+
# @return [Symbol] the default parser type (defaults to :ruby)
|
86
|
+
attr_reader :parser_type
|
87
|
+
|
88
|
+
def parser_type=(value)
|
89
|
+
@parser_type = validated_parser_type(value)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Parses a path or set of paths
|
93
|
+
#
|
94
|
+
# @param [String, Array<String>] paths a path, glob, or list of paths to
|
95
|
+
# parse
|
96
|
+
# @param [Array<String, Regexp>] excluded a list of excluded path matchers
|
97
|
+
# @param [Fixnum] level the logger level to use during parsing. See
|
98
|
+
# {YARD::Logger}
|
99
|
+
# @return [void]
|
100
|
+
def parse(paths = DEFAULT_PATH_GLOB, excluded = [], level = log.level)
|
101
|
+
log.debug("Parsing #{paths.inspect} with `#{parser_type}` parser")
|
102
|
+
excluded = excluded.map do |path|
|
103
|
+
case path
|
104
|
+
when Regexp; path
|
105
|
+
else Regexp.new(path.to_s, Regexp::IGNORECASE)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
files = [paths].flatten.
|
109
|
+
map {|p| File.directory?(p) ? "#{p}/**/*.{rb,c,cc,cxx,cpp}" : p }.
|
110
|
+
map {|p| p.include?("*") ? Dir[p].sort_by {|d| [d.length, d] } : p }.flatten.
|
111
|
+
reject {|p| !File.file?(p) || excluded.any? {|re| p =~ re } }
|
112
|
+
|
113
|
+
log.enter_level(level) do
|
114
|
+
parse_in_order(*files.uniq)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Parses a string +content+
|
119
|
+
#
|
120
|
+
# @param [String] content the block of code to parse
|
121
|
+
# @param [Symbol] ptype the parser type to use. See {parser_type}.
|
122
|
+
# @return the parser object that was used to parse +content+
|
123
|
+
def parse_string(content, ptype = parser_type)
|
124
|
+
new(ptype).parse(StringIO.new(content))
|
125
|
+
end
|
126
|
+
|
127
|
+
# Tokenizes but does not parse the block of code
|
128
|
+
#
|
129
|
+
# @param [String] content the block of code to tokenize
|
130
|
+
# @param [Symbol] ptype the parser type to use. See {parser_type}.
|
131
|
+
# @return [Array] a list of tokens
|
132
|
+
def tokenize(content, ptype = parser_type)
|
133
|
+
new(ptype).tokenize(content)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Registers a new parser type.
|
137
|
+
#
|
138
|
+
# @example Registering a parser for "java" files
|
139
|
+
# SourceParser.register_parser_type :java, JavaParser, 'java'
|
140
|
+
# @param [Symbol] type a symbolic name for the parser type
|
141
|
+
# @param [Base] parser_klass a class that implements parsing and tokenization
|
142
|
+
# @param [Array<String>, String, Regexp] extensions a list of extensions or a
|
143
|
+
# regex to match against the file extension
|
144
|
+
# @return [void]
|
145
|
+
# @see Parser::Base
|
146
|
+
def register_parser_type(type, parser_klass, extensions = nil)
|
147
|
+
unless Base > parser_klass
|
148
|
+
raise ArgumentError, "expecting parser_klass to be a subclass of YARD::Parser::Base"
|
149
|
+
end
|
150
|
+
parser_type_extensions[type.to_sym] = extensions if extensions
|
151
|
+
parser_types[type.to_sym] = parser_klass
|
152
|
+
end
|
153
|
+
|
154
|
+
# @return [Hash{Symbol=>Object}] a list of registered parser types
|
155
|
+
# @private
|
156
|
+
# @since 0.5.6
|
157
|
+
def parser_types; @@parser_types ||= {} end
|
158
|
+
def parser_types=(value) @@parser_types = value end
|
159
|
+
|
160
|
+
# @return [Hash] a list of registered parser type extensions
|
161
|
+
# @private
|
162
|
+
# @since 0.5.6
|
163
|
+
def parser_type_extensions; @@parser_type_extensions ||= {} end
|
164
|
+
def parser_type_extensions=(value) @@parser_type_extensions = value end
|
165
|
+
|
166
|
+
# Finds a parser type that is registered for the extension. If no
|
167
|
+
# type is found, the default Ruby type is returned.
|
168
|
+
#
|
169
|
+
# @return [Symbol] the parser type to be used for the extension
|
170
|
+
# @since 0.5.6
|
171
|
+
def parser_type_for_extension(extension)
|
172
|
+
type = parser_type_extensions.find do |_t, exts|
|
173
|
+
[exts].flatten.any? {|ext| ext === extension }
|
174
|
+
end
|
175
|
+
validated_parser_type(type ? type.first : :ruby)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Returns the validated parser type. Basically, enforces that :ruby
|
179
|
+
# type is never set if the Ripper library is not available
|
180
|
+
#
|
181
|
+
# @param [Symbol] type the parser type to set
|
182
|
+
# @return [Symbol] the validated parser type
|
183
|
+
# @private
|
184
|
+
def validated_parser_type(type)
|
185
|
+
!defined?(::Ripper) && type == :ruby ? :ruby18 : type
|
186
|
+
end
|
187
|
+
|
188
|
+
# @group Parser Callbacks
|
189
|
+
|
190
|
+
# Registers a callback to be called before a list of files is parsed
|
191
|
+
# via {parse}. The block passed to this method will be called on
|
192
|
+
# subsequent parse calls.
|
193
|
+
#
|
194
|
+
# @example Installing a simple callback
|
195
|
+
# SourceParser.before_parse_list do |files, globals|
|
196
|
+
# puts "Starting to parse..."
|
197
|
+
# end
|
198
|
+
# YARD.parse('lib/**/*.rb')
|
199
|
+
# # prints "Starting to parse..."
|
200
|
+
#
|
201
|
+
# @example Setting global state
|
202
|
+
# SourceParser.before_parse_list do |files, globals|
|
203
|
+
# globals.method_count = 0
|
204
|
+
# end
|
205
|
+
# SourceParser.after_parse_list do |files, globals|
|
206
|
+
# puts "Found #{globals.method_count} methods"
|
207
|
+
# end
|
208
|
+
# class MyCountHandler < Handlers::Ruby::Base
|
209
|
+
# handles :def, :defs
|
210
|
+
# process { globals.method_count += 1 }
|
211
|
+
# end
|
212
|
+
# YARD.parse
|
213
|
+
# # Prints: "Found 37 methods"
|
214
|
+
#
|
215
|
+
# @example Using a global callback to cancel parsing
|
216
|
+
# SourceParser.before_parse_list do |files, globals|
|
217
|
+
# return false if files.include?('foo.rb')
|
218
|
+
# end
|
219
|
+
#
|
220
|
+
# YARD.parse(['foo.rb', 'bar.rb']) # callback cancels this method
|
221
|
+
# YARD.parse('bar.rb') # parses normally
|
222
|
+
#
|
223
|
+
# @yield [files, globals] the yielded block is called once before
|
224
|
+
# parsing all files
|
225
|
+
# @yieldparam [Array<String>] files the list of files that will be parsed.
|
226
|
+
# @yieldparam [OpenStruct] globals a global structure to store arbitrary
|
227
|
+
# state for post processing (see {Handlers::Processor#globals})
|
228
|
+
# @yieldreturn [Boolean] if the block returns +false+, parsing is
|
229
|
+
# cancelled.
|
230
|
+
# @return [Proc] the yielded block
|
231
|
+
# @see after_parse_list
|
232
|
+
# @see before_parse_file
|
233
|
+
# @since 0.7.0
|
234
|
+
def before_parse_list(&block)
|
235
|
+
before_parse_list_callbacks << block
|
236
|
+
end
|
237
|
+
|
238
|
+
# Registers a callback to be called after a list of files is parsed
|
239
|
+
# via {parse}. The block passed to this method will be called on
|
240
|
+
# subsequent parse calls.
|
241
|
+
#
|
242
|
+
# @example Printing results after parsing occurs
|
243
|
+
# SourceParser.after_parse_list do
|
244
|
+
# puts "Finished parsing!"
|
245
|
+
# end
|
246
|
+
# YARD.parse
|
247
|
+
# # Prints "Finished parsing!" after parsing files
|
248
|
+
# @yield [files, globals] the yielded block is called once before
|
249
|
+
# parsing all files
|
250
|
+
# @yieldparam [Array<String>] files the list of files that will be parsed.
|
251
|
+
# @yieldparam [OpenStruct] globals a global structure to store arbitrary
|
252
|
+
# state for post processing (see {Handlers::Processor#globals})
|
253
|
+
# @yieldreturn [void] the return value for the block is ignored.
|
254
|
+
# @return [Proc] the yielded block
|
255
|
+
# @see before_parse_list
|
256
|
+
# @see before_parse_file
|
257
|
+
# @since 0.7.0
|
258
|
+
def after_parse_list(&block)
|
259
|
+
after_parse_list_callbacks << block
|
260
|
+
end
|
261
|
+
|
262
|
+
# Registers a callback to be called before an individual file is parsed.
|
263
|
+
# The block passed to this method will be called on subsequent parse
|
264
|
+
# calls.
|
265
|
+
#
|
266
|
+
# To register a callback that is called before the entire list of files
|
267
|
+
# is processed, see {before_parse_list}.
|
268
|
+
#
|
269
|
+
# @example Installing a simple callback
|
270
|
+
# SourceParser.before_parse_file do |parser|
|
271
|
+
# puts "I'm parsing #{parser.file}"
|
272
|
+
# end
|
273
|
+
# YARD.parse('lib/**/*.rb')
|
274
|
+
# # prints:
|
275
|
+
# "I'm parsing lib/foo.rb"
|
276
|
+
# "I'm parsing lib/foo_bar.rb"
|
277
|
+
# "I'm parsing lib/last_file.rb"
|
278
|
+
#
|
279
|
+
# @example Cancel parsing of any test_*.rb files
|
280
|
+
# SourceParser.before_parse_file do |parser|
|
281
|
+
# return false if parser.file =~ /^test_.+\.rb$/
|
282
|
+
# end
|
283
|
+
#
|
284
|
+
# @yield [parser] the yielded block is called once before each
|
285
|
+
# file that is parsed. This might happen many times for a single
|
286
|
+
# codebase.
|
287
|
+
# @yieldparam [SourceParser] parser the parser object that will {#parse}
|
288
|
+
# the file.
|
289
|
+
# @yieldreturn [Boolean] if the block returns +false+, parsing for
|
290
|
+
# the file is cancelled.
|
291
|
+
# @return [Proc] the yielded block
|
292
|
+
# @see after_parse_file
|
293
|
+
# @see before_parse_list
|
294
|
+
# @since 0.7.0
|
295
|
+
def before_parse_file(&block)
|
296
|
+
before_parse_file_callbacks << block
|
297
|
+
end
|
298
|
+
|
299
|
+
# Registers a callback to be called after an individual file is parsed.
|
300
|
+
# The block passed to this method will be called on subsequent parse
|
301
|
+
# calls.
|
302
|
+
#
|
303
|
+
# To register a callback that is called after the entire list of files
|
304
|
+
# is processed, see {after_parse_list}.
|
305
|
+
#
|
306
|
+
# @example Printing the length of each file after it is parsed
|
307
|
+
# SourceParser.after_parse_file do |parser|
|
308
|
+
# puts "#{parser.file} is #{parser.contents.size} characters"
|
309
|
+
# end
|
310
|
+
# YARD.parse('lib/**/*.rb')
|
311
|
+
# # prints:
|
312
|
+
# "lib/foo.rb is 1240 characters"
|
313
|
+
# "lib/foo_bar.rb is 248 characters"
|
314
|
+
#
|
315
|
+
# @yield [parser] the yielded block is called once after each file
|
316
|
+
# that is parsed. This might happen many times for a single codebase.
|
317
|
+
# @yieldparam [SourceParser] parser the parser object that parsed
|
318
|
+
# the file.
|
319
|
+
# @yieldreturn [void] the return value for the block is ignored.
|
320
|
+
# @return [Proc] the yielded block
|
321
|
+
# @see before_parse_file
|
322
|
+
# @see after_parse_list
|
323
|
+
# @since 0.7.0
|
324
|
+
def after_parse_file(&block)
|
325
|
+
after_parse_file_callbacks << block
|
326
|
+
end
|
327
|
+
|
328
|
+
# @return [Array<Proc>] the list of callbacks to be called before
|
329
|
+
# parsing a list of files. Should only be used for testing.
|
330
|
+
# @since 0.7.0
|
331
|
+
def before_parse_list_callbacks
|
332
|
+
@before_parse_list_callbacks ||= []
|
333
|
+
end
|
334
|
+
|
335
|
+
# @return [Array<Proc>] the list of callbacks to be called after
|
336
|
+
# parsing a list of files. Should only be used for testing.
|
337
|
+
# @since 0.7.0
|
338
|
+
def after_parse_list_callbacks
|
339
|
+
@after_parse_list_callbacks ||= []
|
340
|
+
end
|
341
|
+
|
342
|
+
# @return [Array<Proc>] the list of callbacks to be called before
|
343
|
+
# parsing a file. Should only be used for testing.
|
344
|
+
# @since 0.7.0
|
345
|
+
def before_parse_file_callbacks
|
346
|
+
@before_parse_file_callbacks ||= []
|
347
|
+
end
|
348
|
+
|
349
|
+
# @return [Array<Proc>] the list of callbacks to be called after
|
350
|
+
# parsing a file. Should only be used for testing.
|
351
|
+
# @since 0.7.0
|
352
|
+
def after_parse_file_callbacks
|
353
|
+
@after_parse_file_callbacks ||= []
|
354
|
+
end
|
355
|
+
|
356
|
+
# @endgroup
|
357
|
+
|
358
|
+
private
|
359
|
+
|
360
|
+
# Parses a list of files in a queue.
|
361
|
+
#
|
362
|
+
# @param [Array<String>] files a list of files to queue for parsing
|
363
|
+
# @return [void]
|
364
|
+
def parse_in_order(*files)
|
365
|
+
global_state = OpenStruct.new
|
366
|
+
|
367
|
+
return if before_parse_list_callbacks.any? do |cb|
|
368
|
+
cb.call(files, global_state) == false
|
369
|
+
end
|
370
|
+
|
371
|
+
OrderedParser.new(global_state, files).parse
|
372
|
+
|
373
|
+
after_parse_list_callbacks.each do |cb|
|
374
|
+
cb.call(files, global_state)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
register_parser_type :ruby, Ruby::RubyParser
|
380
|
+
register_parser_type :ruby18, Ruby::Legacy::RubyParser
|
381
|
+
register_parser_type :c, C::CParser, ['c', 'cc', 'cxx', 'cpp']
|
382
|
+
|
383
|
+
self.parser_type = :ruby
|
384
|
+
|
385
|
+
# @return [String] the filename being parsed by the parser.
|
386
|
+
attr_accessor :file
|
387
|
+
|
388
|
+
# @return [Symbol] the parser type associated with the parser instance.
|
389
|
+
# This should be set by the {#initialize constructor}.
|
390
|
+
attr_reader :parser_type
|
391
|
+
|
392
|
+
# @return [OpenStruct] an open struct containing arbitrary global state
|
393
|
+
# shared between files and handlers.
|
394
|
+
# @since 0.7.0
|
395
|
+
attr_reader :globals
|
396
|
+
|
397
|
+
# @return [String] the contents of the file to be parsed
|
398
|
+
# @since 0.7.0
|
399
|
+
attr_reader :contents
|
400
|
+
|
401
|
+
# @overload initialize(parser_type = SourceParser.parser_type, globals = nil)
|
402
|
+
# Creates a new parser object for code parsing with a specific parser type.
|
403
|
+
#
|
404
|
+
# @param [Symbol] parser_type the parser type to use
|
405
|
+
# @param [OpenStruct] globals global state to be re-used across separate source files
|
406
|
+
def initialize(parser_type = SourceParser.parser_type, globals1 = nil, globals2 = nil)
|
407
|
+
globals = [true, false].include?(globals1) ? globals2 : globals1
|
408
|
+
@file = '(stdin)'
|
409
|
+
@globals = globals || OpenStruct.new
|
410
|
+
self.parser_type = parser_type
|
411
|
+
end
|
412
|
+
|
413
|
+
# The main parser method. This should not be called directly. Instead,
|
414
|
+
# use the class methods {parse} and {parse_string}.
|
415
|
+
#
|
416
|
+
# @param [String, #read, Object] content the source file to parse
|
417
|
+
# @return [Object, nil] the parser object used to parse the source
|
418
|
+
def parse(content = __FILE__)
|
419
|
+
case content
|
420
|
+
when String
|
421
|
+
@file = File.cleanpath(content)
|
422
|
+
content = convert_encoding(String.new(File.read_binary(file)))
|
423
|
+
checksum = Registry.checksum_for(content)
|
424
|
+
return if Registry.checksums[file] == checksum
|
425
|
+
|
426
|
+
if Registry.checksums.key?(file)
|
427
|
+
log.info "File '#{file}' was modified, re-processing..."
|
428
|
+
end
|
429
|
+
Registry.checksums[@file] = checksum
|
430
|
+
self.parser_type = parser_type_for_filename(file)
|
431
|
+
else
|
432
|
+
content = content.read if content.respond_to? :read
|
433
|
+
end
|
434
|
+
|
435
|
+
@contents = content
|
436
|
+
@parser = parser_class.new(content, file)
|
437
|
+
|
438
|
+
self.class.before_parse_file_callbacks.each do |cb|
|
439
|
+
return @parser if cb.call(self) == false
|
440
|
+
end
|
441
|
+
|
442
|
+
@parser.parse
|
443
|
+
post_process
|
444
|
+
|
445
|
+
self.class.after_parse_file_callbacks.each do |cb|
|
446
|
+
cb.call(self)
|
447
|
+
end
|
448
|
+
|
449
|
+
@parser
|
450
|
+
rescue ArgumentError, NotImplementedError => e
|
451
|
+
log.warn("Cannot parse `#{file}': #{e.message}")
|
452
|
+
log.backtrace(e, :warn)
|
453
|
+
rescue ParserSyntaxError => e
|
454
|
+
log.warn(e.message.capitalize)
|
455
|
+
log.backtrace(e, :warn)
|
456
|
+
end
|
457
|
+
|
458
|
+
# Tokenizes but does not parse the block of code using the current {#parser_type}
|
459
|
+
#
|
460
|
+
# @param [String] content the block of code to tokenize
|
461
|
+
# @return [Array] a list of tokens
|
462
|
+
def tokenize(content)
|
463
|
+
@parser = parser_class.new(content, file)
|
464
|
+
@parser.tokenize
|
465
|
+
end
|
466
|
+
|
467
|
+
private
|
468
|
+
|
469
|
+
# Searches for encoding line and forces encoding
|
470
|
+
# @since 0.5.3
|
471
|
+
def convert_encoding(content)
|
472
|
+
return content unless content.respond_to?(:force_encoding)
|
473
|
+
if content =~ ENCODING_LINE
|
474
|
+
content.force_encoding($1)
|
475
|
+
else
|
476
|
+
content.force_encoding('binary')
|
477
|
+
ENCODING_BYTE_ORDER_MARKS.each do |encoding, bom|
|
478
|
+
bom.force_encoding('binary')
|
479
|
+
if content[0, bom.size] == bom
|
480
|
+
content.force_encoding(encoding)
|
481
|
+
return content
|
482
|
+
end
|
483
|
+
end
|
484
|
+
content.force_encoding('utf-8') # UTF-8 is default encoding
|
485
|
+
content
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
# Runs a {Handlers::Processor} object to post process the parsed statements.
|
490
|
+
# @return [void]
|
491
|
+
def post_process
|
492
|
+
return unless @parser.respond_to?(:enumerator)
|
493
|
+
|
494
|
+
enumerator = @parser.enumerator
|
495
|
+
if enumerator
|
496
|
+
post = Handlers::Processor.new(self)
|
497
|
+
post.process(enumerator)
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
def parser_type=(value)
|
502
|
+
@parser_type = self.class.validated_parser_type(value)
|
503
|
+
end
|
504
|
+
|
505
|
+
# Guesses the parser type to use depending on the file extension.
|
506
|
+
#
|
507
|
+
# @param [String] filename the filename to use to guess the parser type
|
508
|
+
# @return [Symbol] a parser type that matches the filename
|
509
|
+
def parser_type_for_filename(filename)
|
510
|
+
ext = (File.extname(filename)[1..-1] || "").downcase
|
511
|
+
type = self.class.parser_type_for_extension(ext)
|
512
|
+
parser_type == :ruby18 && type == :ruby ? :ruby18 : type
|
513
|
+
end
|
514
|
+
|
515
|
+
# @since 0.5.6
|
516
|
+
def parser_class
|
517
|
+
klass = self.class.parser_types[parser_type]
|
518
|
+
unless klass
|
519
|
+
raise ArgumentError, "invalid parser type '#{parser_type}' or unrecognized file", caller[1..-1]
|
520
|
+
end
|
521
|
+
|
522
|
+
klass
|
523
|
+
end
|
524
|
+
end
|
525
|
+
end
|
526
|
+
end
|