diff -Nur --exclude=doc ruby-1.8.3/lib/rdoc/Makefile ../rdoc-dennou-20051213/Makefile --- ruby-1.8.3/lib/rdoc/Makefile 1970-01-01 09:00:00.000000000 +0900 +++ ../rdoc-dennou-20051213/Makefile 2005-11-15 18:27:19.000000000 +0900 @@ -0,0 +1,13 @@ +all: + +doc: + rdoc --op doc --title "Rdoc-Dennou Documentations" \ + --charset euc-jp --inline-source --line-numbers \ + --main README.ja \ + README README.ja README.org *.rb */*.rb */*/*.rb + +clean: clean-doc + test "`find . -name '*~'`" = "" || rm `find . -name '*~'` + +clean-doc: + test ! -d doc || rm -rf doc diff -Nur --exclude=doc ruby-1.8.3/lib/rdoc/README ../rdoc-dennou-20051213/README --- ruby-1.8.3/lib/rdoc/README 2004-12-04 14:38:15.000000000 +0900 +++ ../rdoc-dennou-20051213/README 2005-11-02 17:10:24.000000000 +0900 @@ -1,492 +1,3 @@ -= RDOC - Ruby Documentation System += RDOC changed for enhancement of Fortran95 parser (for GFD Dennou Club dcmodel project) -This package contains Rdoc and SimpleMarkup. Rdoc is an application -that produces documentation for one or more Ruby source files. We work -similarly to JavaDoc, parsing the source, and extracting the -definition for classes, modules, and methods (along with includes and -requires). We associate with these optional documentation contained -in the immediately preceding comment block, and then render the result -using a pluggable output formatter. (Currently, HTML is the only -supported format. Markup is a library that converts plain text into -various output formats. The Markup library is used to interpret the -comment blocks that Rdoc uses to document methods, classes, and so on. - -This library contains two packages, rdoc itself and a text markup -library, 'markup'. - -== Roadmap - -* If you want to use Rdoc to create documentation for your Ruby source - files, read on. -* If you want to include extensions written in C, see rdoc/parsers/parse_c.rb. -* For information on the various markups available in comment - blocks, see markup/simple_markup.rb. -* If you want to drive Rdoc programatically, see RDoc::RDoc. -* If you want to use the library to format text blocks into HTML, - have a look at SM::SimpleMarkup. -* If you want to try writing your own HTML output template, see - RDoc::Page. - -== Summary - -Once installed, you can create documentation using the 'rdoc' command -(the command is 'rdoc.bat' under Windows) - - % rdoc [options] [names...] - -Type "rdoc --help" for an up-to-date option summary. - -A typical use might be to generate documentation for a package of Ruby -source (such as rdoc itself). - - % rdoc - -This command generates documentation for all the Ruby and C source -files in and below the current directory. These will be stored in a -documentation tree starting in the subdirectory 'doc'. - -You can make this slightly more useful for your readers by having the -index page contain the documentation for the primary file. In our -case, we could type - - % rdoc --main rdoc/rdoc.rb - -You'll find information on the various formatting tricks you can use -in comment blocks in the documentation this generates. - -RDoc uses file extensions to determine how to process each file. File -names ending .rb and .rbw are assumed to be Ruby -source. Files ending .c are parsed as C files. All other -files are assumed to contain just SimpleMarkup-style markup (with or -without leading '#' comment markers). If directory names are passed to -RDoc, they are scanned recursively for C and Ruby source files only. - -== Credits - -* The Ruby parser in rdoc/parse.rb is based heavily on the outstanding - work of Keiju ISHITSUKA of Nippon Rational Inc, who produced the Ruby - parser for irb and the rtags package. - -* Code to diagram classes and modules was written by Sergey A Yanovitsky - (Jah) of Enticla. - -* Charset patch from MoonWolf. - -* Rich Kilmer wrote the kilmer.rb output template. - -* Dan Brickley led the design of the RDF format. - -== License - -RDoc is Copyright (c) 2001-2003 Dave Thomas, The Pragmatic Programmers. It -is free software, and may be redistributed under the terms specified -in the README file of the Ruby distribution. - - ----- - -= Usage - -RDoc is invoked from the command line using: - - % rdoc [name...] - -Files are parsed, and the information they contain collected, before -any output is produced. This allows cross references between all files -to be resolved. If a name is a directory, it is traversed. If no -names are specified, all Ruby files in the current directory (and -subdirectories) are processed. - -Options are: - -[--accessor name[,name...]] - specifies the name(s) of additional methods that should be treated - as if they were attr_xxx methods. Specifying - "--accessor db_opt" means lines such as - - db_opt :name, :age - - will get parsed and displayed in the documentation. Each name may have an - optional "=flagtext" appended, in which case the given flagtext will appear - where (for example) the 'rw' appears for attr_accessor. - -[--all] - include protected and private methods in the output (by default - only public methods are included) - -[--charset _charset_] - Set the character set for the generated HTML. - -[--diagram] - include diagrams showing modules and classes. This is currently - an experimental feature, and may not be supported by all output - templates. You need dot V1.8.6 or later to use the --diagram - option correctly (http://www.research.att.com/sw/tools/graphviz/). - -[--exclude pattern] - exclude files and directories matching this pattern from processing - -[--extension new=old] - treat files ending .new as if they ended - .old. Saying '--extension cgi=rb' causes RDoc to treat .cgi - files as Ruby source. - -[fileboxes] - Classes are put in boxes which represents files, where these - classes reside. Classes shared between more than one file are - shown with list of files that sharing them. Silently discarded if - --diagram is not given Experimental. - -[--fmt _fmt_] - generate output in a particular format. - -[--help] - generate a usage summary. - -[--help-output] - explain the various output options. - -[--image-format gif/png/jpg/jpeg] - sets output image format for diagrams. Can be png, gif, jpeg, - jpg. If this option is omitted, png is used. Requires --diagram. - -[--include dir,...] - specify one or more directories to be searched when satisfying - :+include+: directives. Multiple --include options may be - given. The directory containing the file currently being processed - is always searched. - -[--inline-source] - By default, the source code of methods is shown in a popup. With - this option, it's displayed inline. - -[line-numbers] - include line numbers in the source code - -[--main _name_] - the class of module _name_ will appear on the index page. If you - want to set a particular file as a main page (a README, for - example) simply specifiy its name as the first on the command - line. - -[--merge] - when generating _ri_ output, if classes being processed already - exist in the destination directory, merge in the current details - rather than overwrite them. - -[--one-file] - place all the output into a single file - -[--op _dir_] - set the output directory to _dir_ (the default is the directory - "doc") - -[--op-name _name_] - set the name of the output. Has no effect for HTML. - "doc") - -[--opname _name_] - set the output name (has no effect for HTML). - -[--promiscuous] - If a module or class is defined in more than one source file, and - you click on a particular file's name in the top navigation pane, - RDoc will normally only show you the inner classes and modules of - that class that are defined in the particular file. Using this - option makes it show all classes and modules defined in the class, - regardless of the file they were defined in. - -[--quiet] - do not display progress messages - -[--ri, --ri-site, _and_ --ri-system] - generate output than can be read by the _ri_ command-line tool. - By default --ri places its output in ~/.rdoc, --ri-site in - $datadir/ri//site, and --ri-system in - $datadir/ri//system. All can be overridden with a subsequent - --op option. All default directories are in ri's default search - path. - -[--show-hash] - A name of the form #name in a comment is a possible hyperlink to - an instance method name. When displayed, the '#' is removed unless - this option is specified - -[--style stylesheet url] - specifies the URL of an external stylesheet to use (rather than - generating one of our own) - -[tab-width _n_] - set the width of tab characters (default 8) - -[--template name] - specify an alternate template to use when generating output (the - default is 'standard'). This template should be in a directory - accessible via $: as rdoc/generators/xxxx_template, where 'xxxx' - depends on the output formatter. - -[--version] - display RDoc's version - -[--webcvs _url_] - Specify a URL for linking to a web frontend to CVS. If the URL - contains a '\%s', the name of the current file will be - substituted; if the URL doesn't contain a '\%s', the filename will - be appended to it. - -= Example - -A typical small Ruby program commented using RDoc might be as follows. You -can see the formatted result in EXAMPLE.rb and Anagram. - - :include: EXAMPLE.rb - -= Markup - -Comment blocks can be written fairly naturally, either using '#' on -successive lines of the comment, or by including the comment in -an =begin/=end block. If you use the latter form, the =begin line -must be flagged with an RDoc tag: - - =begin rdoc - Documentation to - be processed by RDoc. - =end - -Paragraphs are lines that share the left margin. Text indented past -this margin are formatted verbatim. - -1. Lists are typed as indented paragraphs with: - * a '*' or '-' (for bullet lists) - * a digit followed by a period for - numbered lists - * an upper or lower case letter followed - by a period for alpha lists. - - For example, the input that produced the above paragraph looked like - 1. Lists are typed as indented - paragraphs with: - * a '*' or '-' (for bullet lists) - * a digit followed by a period for - numbered lists - * an upper or lower case letter followed - by a period for alpha lists. - -2. Labeled lists (sometimes called description - lists) are typed using square brackets for the label. - [cat] small domestic animal - [+cat+] command to copy standard input - -3. Labeled lists may also be produced by putting a double colon - after the label. This sets the result in tabular form, so the - descriptions all line up. This was used to create the 'author' - block at the bottom of this description. - cat:: small domestic animal - +cat+:: command to copy standard input - - For both kinds of labeled lists, if the body text starts on the same - line as the label, then the start of that text determines the block - indent for the rest of the body. The text may also start on the line - following the label, indented from the start of the label. This is - often preferable if the label is long. Both the following are - valid labeled list entries: - - --output name [, name]:: - specify the name of one or more output files. If multiple - files are present, the first is used as the index. - - --quiet::: do not output the names, sizes, byte counts, - index areas, or bit ratios of units as - they are processed. - -4. Headings are entered using equals signs - - = Level One Heading - == Level Two Heading - and so on - -5. Rules (horizontal lines) are entered using three or - more hyphens. - -6. Non-verbatim text can be marked up: - - _italic_:: \_word_ or \text - *bold*:: \*word* or \text - +typewriter+:: \+word+ or \text - - The first form only works around 'words', where a word is a - sequence of upper and lower case letters and underscores. Putting a - backslash before inline markup stops it being interpreted, which is - how I created the table above: - - _italic_:: \_word_ or \text - *bold*:: \*word* or \text - +typewriter+:: \+word+ or \text - -7. Names of classes, source files, and any method names - containing an underscore or preceded by a hash - character are automatically hyperlinked from - comment text to their description. - -8. Hyperlinks to the web starting http:, mailto:, ftp:, or www. are - recognized. An HTTP url that references an external image file is - converted into an inline . Hyperlinks starting 'link:' are - assumed to refer to local files whose path is relative to the --op - directory. - - Hyperlinks can also be of the form label[url], in which - case the label is used in the displayed text, and url is - used as the target. If label contains multiple words, - put it in braces: {multi word label}[url]. - -9. Method parameter lists are extracted and displayed with - the method description. If a method calls +yield+, then - the parameters passed to yield will also be displayed: - - def fred - ... - yield line, address - - This will get documented as - - fred() { |line, address| ... } - - You can override this using a comment containing - ':yields: ...' immediately after the method definition - - def fred # :yields: index, position - ... - yield line, address - - which will get documented as - - fred() { |index, position| ... } - - -10. ':yields:' is an example of a documentation modifier. These appear - immediately after the start of the document element they are modifying. - Other modifiers include - - [:nodoc:[all]] - don't include this element in the documentation. For classes - and modules, the methods, aliases, constants, and attributes - directly within the affected class or module will also be - omitted. By default, though, modules and classes within that - class of module _will_ be documented. This is turned off by - adding the +all+ modifier. - - module SM #:nodoc: - class Input - end - end - module Markup #:nodoc: all - class Output - end - end - - In the above code, only class SM::Input will be - documented. - - [:doc:] - force a method or attribute to be documented even if it - wouldn't otherwise be. Useful if, for example, you want to - include documentation of a particular private method. - - [:notnew:] - only applicable to the +initialize+ instance method. Normally - RDoc assumes that the documentation and parameters for - #initialize are actually for the ::new method, and so fakes - out a ::new for the class. THe :notnew: modifier stops - this. Remember that #initialize is protected, so you won't - see the documentation unless you use the -a command line - option. - - -11. RDoc stops processing comments if it finds a comment - line containing '#--'. This can be used to - separate external from internal comments, or - to stop a comment being associated with a method, - class, or module. Commenting can be turned back on with - a line that starts '#++'. - - # Extract the age and calculate the - # date-of-birth. - #-- - # FIXME: fails if the birthday falls on - # February 29th - #++ - # The DOB is returned as a Time object. - - def get_dob(person) - ... - -12. Comment blocks can contain other directives: - - [:section: title] - Starts a new section in the output. The title following - :section: is used as the section heading, and the - remainder of the comment containing the section is used as - introductory text. Subsequent methods, aliases, attributes, - and classes will be documented in this section. A :section: - comment block may have one or more lines before the :section: - directive. These will be removed, and any identical lines at - the end of the block are also removed. This allows you to add - visual cues such as - - # ---------------------------------------- - # :section: My Section - # This is the section that I wrote. - # See it glisten in the noon-day sun. - # ---------------------------------------- - - [call-seq:] - lines up to the next blank line in the comment are treated as - the method's calling sequence, overriding the - default parsing of method parameters and yield arguments. - - [:include:filename] - include the contents of the named file at this point. The - file will be searched for in the directories listed by - the --include option, or in the current - directory by default. The contents of the file will be - shifted to have the same indentation as the ':' at the - start of the :include: directive. - - [:title:text] - Sets the title for the document. Equivalent to the --title command - line parameter. (The command line parameter overrides any :title: - directive in the source). - - [:enddoc:] - Document nothing further at the current level. - - [:main:name] - Equivalent to the --main command line parameter. - - [:stopdoc: / :startdoc:] - Stop and start adding new documentation elements to the - current container. For example, if a class has a number of - constants that you don't want to document, put a - :stopdoc: before the first, and a - :startdoc: after the last. If you don't specifiy a - :startdoc: by the end of the container, disables - documentation for the entire class or module. - - ---- - -See also markup/simple_markup.rb. - -= Other stuff - -Author:: Dave Thomas -Requires:: Ruby 1.8.1 or later -License:: Copyright (c) 2001-2003 Dave Thomas. - Released under the same license as Ruby. - -== Warranty - -This software is provided "as is" and without any express or -implied warranties, including, without limitation, the implied -warranties of merchantibility and fitness for a particular -purpose. +See README.ja (Sorry, JAPANESE only) diff -Nur --exclude=doc ruby-1.8.3/lib/rdoc/README.ja ../rdoc-dennou-20051213/README.ja --- ruby-1.8.3/lib/rdoc/README.ja 1970-01-01 09:00:00.000000000 +0900 +++ ../rdoc-dennou-20051213/README.ja 2005-12-13 14:27:24.000000000 +0900 @@ -0,0 +1,251 @@ += RDOC Fortran90/95 ソースコード解析機能強化版 (地球流体電脳倶楽部 dcmodel プロジェクト用) + +RDOC の Fortran90/95 ソースコード解析機能を強化するためのパッチを +配布しています. パッチを当てたパッケージも配布しています. +詳しくは, このページの最下部の「沿革」を参照してください. + +== 動作確認 + +このパッケージは Ruby 1.8.2 での動作を確認しています. + +== ダウンロード + +最新版 (バージョン $Name: rdoc-dennou-20051213 $) + +* {Ruby 1.8.3 用のパッチ}[http://www.gfd-dennou.org/library/dcmodel/rdoc-dennou/rdoc-dennou-patch_for_ruby1.8.3] + +* {rdoc-dennou tar.gz パッケージ (Ruby 1.8.3 に上記パッチを当てて tar ボールにしたもの)}[http://www.gfd-dennou.org/library/dcmodel/rdoc-dennou/rdoc-dennou.tgz] + +過去のアーカイブ + +* {パッチ ・ TGZ パッケージ ・ ソースツリーのリスト}[http://www.gfd-dennou.org/library/dcmodel/rdoc-dennou/arch/SIGEN.htm] + +== パッチの利用法 + +まず, {Ruby のホームページ}[http://www.ruby-lang.org/] から +ftp://ftp.ruby-lang.org/pub/ruby/ruby-1.8.3.tar.gz +をダウンロードし, 展開してください. + + % tar xvfz ruby-1.8.3.tar.gz + +このコマンドを実行したディレクトリに上記のパッチファイル +rdoc-dennou-patch_for_ruby1.8.3 を置き, 以下のコマンドでパッチを +当ててください. + + % patch -p0 < rdoc-dennou-patch_for_ruby1.8.3 + +Ruby 自体のインストール方法は{Ruby のホームページ}[http://www.ruby-lang.org/] +を参照してください. + + +== パッケージのインストール + +rdoc-dennou.tgz パッケージをダウンロードした場合は, +以下のように tar コマンドで展開後, +install.rb でインストールを行ってください. +既に rdoc がインストールされている場合, 上書きする可能性があります. + + % tar xvfz rdoc-dennou.tgz + % cd rdoc-dennou + % ruby install.rb + +インストール先のディレクトリや, 変更のためのオプションに関しては, +以下のコマンドで知ることが出来ます. + + % ruby install.rb --help + +== 使用方法 + +実行プログラムがインストールされた場所を環境変数 *PATH* +に設定し, ライブラリがインストールされた場所を環境変数 *RUBYLIB* +に設定してください. + +Fortran95 ファイルが置いてあるディレクトリまで移動し, 以下のコマンドを +実行してください. *doc* ディレクトリ以下にドキュメントが作成されます. + + % rdoc --ignore-case --charset euc-jp --inline-source + +複数のディレクトリに置かれているファイルに +関してドキュメントを作成したい場合は, それらのディレクトリの +親ディレクトリで上記のコマンドを実行してください. +拡張子が +rb+, +rbw+ のファイルは Ruby プログラムとして, +拡張子が +c+, +cc+, +cpp+, +CC+, +cxx+ のファイルは C プログラムとして, +拡張子が f90, F90, f95, F95 +のファイルは Fortran95 プログラムと判定されて解析されます. + +*doc* ディレクトリ以外に出力したい場合は, 以下のように +--op オプションをつけてください. タイトルなどは +--title オプションで変更できます. +また, デフォルトでは Fortran95 の private 属性のサブルーチンや関数 +などはドキュメントに出力されませんが, --all オプションを +つけることで, 全てがドキュメントに出力されます. 開発者用には +こちらの方が良いかもしれません. 一部のファイルのみを +ドキュメント化したい場合は, 引数に src/*.f90 などと +ファイル名を明示的に指定してください. + + % rdoc --ignore-case --charset euc-jp --inline-source \ + --op rdoc --title "RDOC documentations" src/*.f90 test/*.f90 + +詳しいことは +RDOC オリジナルの +README[http://www.ruby-doc.org/stdlib/libdoc/rdoc/rdoc/index.html] +を参照ください. + + +=== 電脳サーバでの利用について + +電脳サーバにはこのパッケージの最新版がインストールされています. +インストール先は dcmodel 領域なので, +以下のようにパスを通して実行してください. + + % RUBYLIB=/GFD_Dennou_Club/ftp/arch/dcmodel/lib/ruby/1.8 \ + /GFD_Dennou_Club/ftp/arch/dcmodel/bin/rdoc \ + --ignore-case --charset euc-jp --inline-source + + +== 書法 + +parsers/parse_f95.rb を参照ください. +ただし, ここに記述されるのは Fortran95 に特有な部分なので, +一般的な部分に関しては +{RDOC のオリジナルの README}[http://www.ruby-doc.org/stdlib/libdoc/rdoc/rdoc/index.html] +を参照ください. +大林さんによる日本語訳が http://www.kmc.gr.jp/~ohai/rdoc.ja.html にあります. + +== サンプル + +* {惑星大気モデル DCPAM のコードリファレンス (製作中)}[http://www.gfd-dennou.org/library/dcpam/dcpam3/dcpam3_current/doc/code_reference/htm] + +== ライセンス + +本家 RDOC に準拠します. +{RDOC オリジナルの README}[http://www.ruby-doc.org/stdlib/libdoc/rdoc/rdoc/index.html] +を参照ください. + +== 動作保障に関して + +本家 RDOC に準拠します. +{RDOC オリジナルの README}[http://www.ruby-doc.org/stdlib/libdoc/rdoc/rdoc/index.html] +を参照ください. + + +== 沿革 + +ここで配布するパッチまたはパッケージは RDOC を主に +Fortran95 のパーサとして利用するため +に改変したものです. 元々 Fortran95 パーサは, RDOC の開発者である +Dave Thomas 氏によって 2003-12-01 に parse_f95.rb として作成され, +以降数度の改変がなされました. RDOC は Ruby CVS リポジトリ +http://www.ruby-lang.org/ja/20020106.html にて開発されており, +この parse_f95.rb も同様です. 2005/10/05 現在の最新版は revision 1.2 +で 2004-01-02 に最終更新されたものです. +http://www.ruby-lang.org/cgi-bin/cvsweb.cgi/ruby/lib/rdoc/parsers/parse_f95.rb +で詳しい情報を参照できます. +なお, Ruby ライブラリのドキュメントは RDOC 形式で +http://www.ruby-doc.org/stdlib/ に公開されています. +RDOC に関してはオリジナルの +README[http://www.ruby-doc.org/stdlib/libdoc/rdoc/rdoc/index.html] +を参照ください. + +本パッケージ内の parsers/parse_f95.rb は, 上記の +revision 1.2 parse_f95.rb を改変したものです. オリジナルに比べ +Fortran95 ソースの解析機能が大幅に向上しています. +(きっとバグも増えていますが). +RDOC 用に Fortran95 のコメントの記述の方法については +parsers/parse_f95.rb を参照してください. + +さらに, parsers/parse_f95.rb 以外のファイルも, Fortran95 ソースから +マニュアルを自動生成するのに必要となるであろう以下の機能を付加しています. +これらも, 2005/10/05 時点の最新版を元に改変しています. + +--ignore-case オプションの追加 :: + Fortran 95 規格では大文字小文字の区別が無いため, + モジュール名, サブルーチン名, 関数名, 定数名, 変数名など, + 大文字小文字の区別を行う必要がありません. + オリジナルの rdoc はクラス名やメソッド名のクロスリファレンスの際に + 大文字小文字を区別しますが, このオプションを与えることにより, + その区別を行わないようにします. + +ファイルのクロスリファレンス :: + クラスやモジュール, メソッドと同様に, ファイル名に関しても + クロスリファレンスを可能にしました. + +-- +# 以降は Fortran とは関係の無い改変 +# +#Ruby ライブラリ IRB::SLex の読み込みについて :: +# Ruby 1.8.2 でも動作するよう, 最新の parse_rb.rb を1つ以前の +# バージョンに戻しています. +# +# +#拡張子cxxも C パーサで解釈 :: +# これは全く Fortran95 とは関係ありません. +# この拡張子 cxxc++ ファイルから +# SWIG[http://swig.shibu.jp/] によって作成されるファイルの拡張子です. +++ + + +今後, これらの改変は可能な範囲で Ruby CVS リポジトリ へとフィードバック +しようと考えています. +(2005/11/15 現在, メンテナの Ryan Davis さんに英語版のパッチを +送ったところです). + +== 連絡先 + +{数値モデリングプロジェクト dcmodel}[http://www.gfd-dennou.org/library/dcmodel/] +のページ末尾を参照ください. + +== 使用上の注意 + +RDOC Fortran90/95 ソースコード解析機能強化版のパッチもしくはパッケージ +(以下, 本パッチもしくはパッケージ) は +研究・教育の場で用いられることを前提としております. 教育現場においては +自由に使用・改変・再配布していただいて結構です. 利用する場合には +{本家 RDOC のライセンス}[http://www.ruby-doc.org/stdlib/libdoc/rdoc/rdoc/index.html] +に従って頂くようお願いします. + +本パッチもしくはパッケージを利用して得られた科学技術的成果を +論文や Web 等にて発表する際には, その旨を記し, リファレンスに挙げて +頂きますようお願いします. + +* 引用例 (和文) + + 森川 靖大, 石渡 正樹, 堀之内 武, 小高 正嗣, 林 祥介, + 数値モデリングプロジェクト dcmodel, 2005: + RDOC Fortran90/95 ソースコード解析機能強化版, + http://www.gfd-dennou.org/library/dcmodel/, 地球流体電脳倶楽部. + +* 引用例 (英文) + + Morikawa,Y., Ishiwatari,M., Horinouchi,T., Odaka,M., Hayashi,Y.-Y., + dcmodel: Numerical Model Porject, 2005: + Enhanced version of RDOC Fortran90/95 parser, + http://www.gfd-dennou.org/library/dcmodel/, GFD Dennou Club. + +== 履歴 + +==== 2005/12/13 + +* parsers/parse_f95.rb に注意事項と Todo を追加. +* 「サンプル」を追加. +* public, private 文を解析する部分のバグを修正. + +==== 2005/12/08 + +* 「使用上の注意」, 「連絡先」を追加. +* 公開アドレスを + http://www.gfd-dennou.org/library/dcmodel/doc/rdoc-dennou/ から + http://www.gfd-dennou.org/library/dcmodel/rdoc-dennou/ へ変更. + (過去の URL もしばらく残しておきます). + +==== 2005/11/28 + +* ":nodoc:" の指定を可能にする. +* サブルーチンや関数内の "contains" 文の処理方法を修正する. +* 表題を変更する. +* 過去のバージョンを公開する. + +==== 2005/11/17 + +* 一通り欲しい機能が揃い, ドキュメントのチェックも行ったので, + タグをつけて公開する. diff -Nur --exclude=doc ruby-1.8.3/lib/rdoc/README.org ../rdoc-dennou-20051213/README.org --- ruby-1.8.3/lib/rdoc/README.org 1970-01-01 09:00:00.000000000 +0900 +++ ../rdoc-dennou-20051213/README.org 2005-11-28 15:19:21.000000000 +0900 @@ -0,0 +1,502 @@ += RDOC - Ruby Documentation System + +== Annotation + +This is copy from RDOC original +README[http://www.ruby-doc.org/stdlib/libdoc/rdoc/rdoc/index.html] + +See README.ja (Sorry, JAPANESE only) + +== Overview + +This package contains Rdoc and SimpleMarkup. Rdoc is an application +that produces documentation for one or more Ruby source files. We work +similarly to JavaDoc, parsing the source, and extracting the +definition for classes, modules, and methods (along with includes and +requires). We associate with these optional documentation contained +in the immediately preceding comment block, and then render the result +using a pluggable output formatter. (Currently, HTML is the only +supported format. Markup is a library that converts plain text into +various output formats. The Markup library is used to interpret the +comment blocks that Rdoc uses to document methods, classes, and so on. + +This library contains two packages, rdoc itself and a text markup +library, 'markup'. + +== Roadmap + +* If you want to use Rdoc to create documentation for your Ruby source + files, read on. +* If you want to include extensions written in C, see rdoc/parsers/parse_c.rb. +* For information on the various markups available in comment + blocks, see markup/simple_markup.rb. +* If you want to drive Rdoc programatically, see RDoc::RDoc. +* If you want to use the library to format text blocks into HTML, + have a look at SM::SimpleMarkup. +* If you want to try writing your own HTML output template, see + RDoc::Page. + +== Summary + +Once installed, you can create documentation using the 'rdoc' command +(the command is 'rdoc.bat' under Windows) + + % rdoc [options] [names...] + +Type "rdoc --help" for an up-to-date option summary. + +A typical use might be to generate documentation for a package of Ruby +source (such as rdoc itself). + + % rdoc + +This command generates documentation for all the Ruby and C source +files in and below the current directory. These will be stored in a +documentation tree starting in the subdirectory 'doc'. + +You can make this slightly more useful for your readers by having the +index page contain the documentation for the primary file. In our +case, we could type + + % rdoc --main rdoc/rdoc.rb + +You'll find information on the various formatting tricks you can use +in comment blocks in the documentation this generates. + +RDoc uses file extensions to determine how to process each file. File +names ending .rb and .rbw are assumed to be Ruby +source. Files ending .c are parsed as C files. All other +files are assumed to contain just SimpleMarkup-style markup (with or +without leading '#' comment markers). If directory names are passed to +RDoc, they are scanned recursively for C and Ruby source files only. + +== Credits + +* The Ruby parser in rdoc/parse.rb is based heavily on the outstanding + work of Keiju ISHITSUKA of Nippon Rational Inc, who produced the Ruby + parser for irb and the rtags package. + +* Code to diagram classes and modules was written by Sergey A Yanovitsky + (Jah) of Enticla. + +* Charset patch from MoonWolf. + +* Rich Kilmer wrote the kilmer.rb output template. + +* Dan Brickley led the design of the RDF format. + +== License + +RDoc is Copyright (c) 2001-2003 Dave Thomas, The Pragmatic Programmers. It +is free software, and may be redistributed under the terms specified +in the README file of the Ruby distribution. + + += Usage + +RDoc is invoked from the command line using: + + % rdoc [name...] + +Files are parsed, and the information they contain collected, before +any output is produced. This allows cross references between all files +to be resolved. If a name is a directory, it is traversed. If no +names are specified, all Ruby files in the current directory (and +subdirectories) are processed. + +Options are: + +[--accessor name[,name...]] + specifies the name(s) of additional methods that should be treated + as if they were attr_xxx methods. Specifying + "--accessor db_opt" means lines such as + + db_opt :name, :age + + will get parsed and displayed in the documentation. Each name may have an + optional "=flagtext" appended, in which case the given flagtext will appear + where (for example) the 'rw' appears for attr_accessor. + +[--all] + include protected and private methods in the output (by default + only public methods are included) + +[--charset _charset_] + Set the character set for the generated HTML. + +[--diagram] + include diagrams showing modules and classes. This is currently + an experimental feature, and may not be supported by all output + templates. You need dot V1.8.6 or later to use the --diagram + option correctly (http://www.research.att.com/sw/tools/graphviz/). + +[--exclude pattern] + exclude files and directories matching this pattern from processing + +[--extension new=old] + treat files ending .new as if they ended + .old. Saying '--extension cgi=rb' causes RDoc to treat .cgi + files as Ruby source. + +[fileboxes] + Classes are put in boxes which represents files, where these + classes reside. Classes shared between more than one file are + shown with list of files that sharing them. Silently discarded if + --diagram is not given Experimental. + +[--fmt _fmt_] + generate output in a particular format. + +[--help] + generate a usage summary. + +[--help-output] + explain the various output options. + +[--ignore-case] + The case of names of classes or modules or methods are ignored. + +[--image-format gif/png/jpg/jpeg] + sets output image format for diagrams. Can be png, gif, jpeg, + jpg. If this option is omitted, png is used. Requires --diagram. + +[--include dir,...] + specify one or more directories to be searched when satisfying + :+include+: directives. Multiple --include options may be + given. The directory containing the file currently being processed + is always searched. + +[--inline-source] + By default, the source code of methods is shown in a popup. With + this option, it's displayed inline. + +[line-numbers] + include line numbers in the source code + +[--main _name_] + the class of module _name_ will appear on the index page. If you + want to set a particular file as a main page (a README, for + example) simply specifiy its name as the first on the command + line. + +[--merge] + when generating _ri_ output, if classes being processed already + exist in the destination directory, merge in the current details + rather than overwrite them. + +[--one-file] + place all the output into a single file + +[--op _dir_] + set the output directory to _dir_ (the default is the directory + "doc") + +[--op-name _name_] + set the name of the output. Has no effect for HTML. + "doc") + +[--opname _name_] + set the output name (has no effect for HTML). + +[--promiscuous] + If a module or class is defined in more than one source file, and + you click on a particular file's name in the top navigation pane, + RDoc will normally only show you the inner classes and modules of + that class that are defined in the particular file. Using this + option makes it show all classes and modules defined in the class, + regardless of the file they were defined in. + +[--quiet] + do not display progress messages + +[--ri, --ri-site, _and_ --ri-system] + generate output than can be read by the _ri_ command-line tool. + By default --ri places its output in ~/.rdoc, --ri-site in + $datadir/ri//site, and --ri-system in + $datadir/ri//system. All can be overridden with a subsequent + --op option. All default directories are in ri's default search + path. + +[--show-hash] + A name of the form #name in a comment is a possible hyperlink to + an instance method name. When displayed, the '#' is removed unless + this option is specified + +[--style stylesheet url] + specifies the URL of an external stylesheet to use (rather than + generating one of our own) + +[tab-width _n_] + set the width of tab characters (default 8) + +[--template name] + specify an alternate template to use when generating output (the + default is 'standard'). This template should be in a directory + accessible via $: as rdoc/generators/xxxx_template, where 'xxxx' + depends on the output formatter. + +[--version] + display RDoc's version + +[--webcvs _url_] + Specify a URL for linking to a web frontend to CVS. If the URL + contains a '\%s', the name of the current file will be + substituted; if the URL doesn't contain a '\%s', the filename will + be appended to it. + += Example + +A typical small Ruby program commented using RDoc might be as follows. You +can see the formatted result in EXAMPLE.rb and Anagram. + + :include: EXAMPLE.rb + += Markup + +Comment blocks can be written fairly naturally, either using '#' on +successive lines of the comment, or by including the comment in +an =begin/=end block. If you use the latter form, the =begin line +must be flagged with an RDoc tag: + + =begin rdoc + Documentation to + be processed by RDoc. + =end + +Paragraphs are lines that share the left margin. Text indented past +this margin are formatted verbatim. + +1. Lists are typed as indented paragraphs with: + * a '*' or '-' (for bullet lists) + * a digit followed by a period for + numbered lists + * an upper or lower case letter followed + by a period for alpha lists. + + For example, the input that produced the above paragraph looked like + 1. Lists are typed as indented + paragraphs with: + * a '*' or '-' (for bullet lists) + * a digit followed by a period for + numbered lists + * an upper or lower case letter followed + by a period for alpha lists. + +2. Labeled lists (sometimes called description + lists) are typed using square brackets for the label. + [cat] small domestic animal + [+cat+] command to copy standard input + +3. Labeled lists may also be produced by putting a double colon + after the label. This sets the result in tabular form, so the + descriptions all line up. This was used to create the 'author' + block at the bottom of this description. + cat:: small domestic animal + +cat+:: command to copy standard input + + For both kinds of labeled lists, if the body text starts on the same + line as the label, then the start of that text determines the block + indent for the rest of the body. The text may also start on the line + following the label, indented from the start of the label. This is + often preferable if the label is long. Both the following are + valid labeled list entries: + + --output name [, name]:: + specify the name of one or more output files. If multiple + files are present, the first is used as the index. + + --quiet::: do not output the names, sizes, byte counts, + index areas, or bit ratios of units as + they are processed. + +4. Headings are entered using equals signs + + = Level One Heading + == Level Two Heading + and so on + +5. Rules (horizontal lines) are entered using three or + more hyphens. + +6. Non-verbatim text can be marked up: + + _italic_:: \_word_ or \text + *bold*:: \*word* or \text + +typewriter+:: \+word+ or \text + + The first form only works around 'words', where a word is a + sequence of upper and lower case letters and underscores. Putting a + backslash before inline markup stops it being interpreted, which is + how I created the table above: + + _italic_:: \_word_ or \text + *bold*:: \*word* or \text + +typewriter+:: \+word+ or \text + +7. Names of classes, source files, and any method names + containing an underscore or preceded by a hash + character are automatically hyperlinked from + comment text to their description. + +8. Hyperlinks to the web starting http:, mailto:, ftp:, or www. are + recognized. An HTTP url that references an external image file is + converted into an inline . Hyperlinks starting 'link:' are + assumed to refer to local files whose path is relative to the --op + directory. + + Hyperlinks can also be of the form label[url], in which + case the label is used in the displayed text, and url is + used as the target. If label contains multiple words, + put it in braces: {multi word label}[url]. + +9. Method parameter lists are extracted and displayed with + the method description. If a method calls +yield+, then + the parameters passed to yield will also be displayed: + + def fred + ... + yield line, address + + This will get documented as + + fred() { |line, address| ... } + + You can override this using a comment containing + ':yields: ...' immediately after the method definition + + def fred # :yields: index, position + ... + yield line, address + + which will get documented as + + fred() { |index, position| ... } + + +10. ':yields:' is an example of a documentation modifier. These appear + immediately after the start of the document element they are modifying. + Other modifiers include + + [:nodoc:[all]] + don't include this element in the documentation. For classes + and modules, the methods, aliases, constants, and attributes + directly within the affected class or module will also be + omitted. By default, though, modules and classes within that + class of module _will_ be documented. This is turned off by + adding the +all+ modifier. + + module SM #:nodoc: + class Input + end + end + module Markup #:nodoc: all + class Output + end + end + + In the above code, only class SM::Input will be + documented. + + [:doc:] + force a method or attribute to be documented even if it + wouldn't otherwise be. Useful if, for example, you want to + include documentation of a particular private method. + + [:notnew:] + only applicable to the +initialize+ instance method. Normally + RDoc assumes that the documentation and parameters for + #initialize are actually for the ::new method, and so fakes + out a ::new for the class. THe :notnew: modifier stops + this. Remember that #initialize is protected, so you won't + see the documentation unless you use the -a command line + option. + + +11. RDoc stops processing comments if it finds a comment + line containing '#--'. This can be used to + separate external from internal comments, or + to stop a comment being associated with a method, + class, or module. Commenting can be turned back on with + a line that starts '#++'. + + # Extract the age and calculate the + # date-of-birth. + #-- + # FIXME: fails if the birthday falls on + # February 29th + #++ + # The DOB is returned as a Time object. + + def get_dob(person) + ... + +12. Comment blocks can contain other directives: + + [:section: title] + Starts a new section in the output. The title following + :section: is used as the section heading, and the + remainder of the comment containing the section is used as + introductory text. Subsequent methods, aliases, attributes, + and classes will be documented in this section. A :section: + comment block may have one or more lines before the :section: + directive. These will be removed, and any identical lines at + the end of the block are also removed. This allows you to add + visual cues such as + + # ---------------------------------------- + # :section: My Section + # This is the section that I wrote. + # See it glisten in the noon-day sun. + # ---------------------------------------- + + [call-seq:] + lines up to the next blank line in the comment are treated as + the method's calling sequence, overriding the + default parsing of method parameters and yield arguments. + + [:include:filename] + include the contents of the named file at this point. The + file will be searched for in the directories listed by + the --include option, or in the current + directory by default. The contents of the file will be + shifted to have the same indentation as the ':' at the + start of the :include: directive. + + [:title:text] + Sets the title for the document. Equivalent to the --title command + line parameter. (The command line parameter overrides any :title: + directive in the source). + + [:enddoc:] + Document nothing further at the current level. + + [:main:name] + Equivalent to the --main command line parameter. + + [:stopdoc: / :startdoc:] + Stop and start adding new documentation elements to the + current container. For example, if a class has a number of + constants that you don't want to document, put a + :stopdoc: before the first, and a + :startdoc: after the last. If you don't specifiy a + :startdoc: by the end of the container, disables + documentation for the entire class or module. + + +--- + +See also markup/simple_markup.rb. + += Other stuff + +Author:: Dave Thomas +Requires:: Ruby 1.8.1 or later +License:: Copyright (c) 2001-2003 Dave Thomas. + Released under the same license as Ruby. + +== Warranty + +This software is provided "as is" and without any express or +implied warranties, including, without limitation, the implied +warranties of merchantibility and fitness for a particular +purpose. diff -Nur --exclude=doc ruby-1.8.3/lib/rdoc/code_objects.rb ../rdoc-dennou-20051213/code_objects.rb --- ruby-1.8.3/lib/rdoc/code_objects.rb 2004-12-04 14:38:15.000000000 +0900 +++ ../rdoc-dennou-20051213/code_objects.rb 2005-10-23 13:53:07.000000000 +0900 @@ -244,8 +244,8 @@ add_to(@attributes, an_attribute) end - def add_alias(an_alias) - meth = find_instance_method_named(an_alias.old_name) + def add_alias(an_alias, ignore_case=nil) + meth = find_instance_method_named(an_alias.old_name, ignore_case) if meth new_meth = AnyMethod.new(an_alias.text, an_alias.new_name) new_meth.is_alias_for = meth @@ -325,16 +325,34 @@ end # Find a named module - def find_module_named(name) - return self if self.name == name - res = @modules[name] || @classes[name] + def find_module_named(name, ignore_case=nil) + res = nil + if !ignore_case + return self if self.name == name + else + return self if self.name.upcase == name.upcase + end + if !ignore_case + res = @modules[name] || @classes[name] + else + @modules.each{ |n, v| + if n.upcase == name.upcase + res = v ; break + end + } + @classes.each{ |n, v| + if n.upcase == name.upcase + res = v ; break + end + } if !res + end return res if res - find_enclosing_module_named(name) + find_enclosing_module_named(name, ignore_case) end # find a module at a higher scope - def find_enclosing_module_named(name) - parent && parent.find_module_named(name) + def find_enclosing_module_named(name, ignore_case=nil) + parent && parent.find_module_named(name, ignore_case) end # Iterate over all the classes and modules in @@ -357,6 +375,10 @@ @constants.each {|c| yield c} end + def each_includes + @includes.each {|i| yield i} + end + # Return the toplevel that owns us def toplevel @@ -371,22 +393,27 @@ name <=> other.name end + # Look up the given filename. + def find_file(file, method=nil, ignore_case=nil) + find_file_named(file, method, ignore_case) + end + # Look up the given symbol. If method is non-nil, then # we assume the symbol references a module that # contains that method - def find_symbol(symbol, method=nil) + def find_symbol(symbol, method=nil, ignore_case=nil) result = nil case symbol when /^::(.*)/ - result = toplevel.find_symbol($1) + result = toplevel.find_symbol($1, nil, ignore_case) when /::/ modules = symbol.split(/::/) unless modules.empty? module_name = modules.shift - result = find_module_named(module_name) + result = find_module_named(module_name, ignore_case) if result modules.each do |module_name| - result = result.find_module_named(module_name) + result = result.find_module_named(module_name, ignore_case) break unless result end end @@ -395,11 +422,12 @@ # if a method is specified, then we're definitely looking for # a module, otherwise it could be any symbol if method - result = find_module_named(symbol) + result = find_module_named(symbol, ignore_case) else - result = find_local_symbol(symbol) + result = find_local_symbol(symbol, ignore_case) if result.nil? - if symbol =~ /^[A-Z]/ + if symbol =~ /^[A-Z]/ || + symbol =~ /^[A-Za-z]/ && ignore_case result = parent while result && result.name != symbol result = result.parent @@ -414,16 +442,40 @@ p method fail end - result = result.find_local_symbol(method) + result = result.find_local_symbol(method, ignore_case) end result end - - def find_local_symbol(symbol) - res = find_method_named(symbol) || - find_constant_named(symbol) || - find_attribute_named(symbol) || - find_module_named(symbol) + + def find_local_symbol(symbol, ignore_case=nil) + res = find_method_named(symbol, ignore_case) || + find_constant_named(symbol, ignore_case) || + find_attribute_named(symbol, ignore_case) || + find_module_named(symbol, ignore_case) + end + + def include_requires?(name, ignore_case=nil) + if self.kind_of? TopLevel + self.requires.each{|r| + if r.name == name || + r.name.upcase == name.upcase && ignore_case + return true + end + } + return false + else + parent.include_requires?(name) + end + end + + def include_includes?(name, ignore_case=nil) + self.includes.each{|i| + if i.name == name || + i.name.upcase == name.upcase && ignore_case + return true + end + } + return false end # Handle sections @@ -436,25 +488,43 @@ private # Find a named method, or return nil - def find_method_named(name) - @method_list.find {|meth| meth.name == name} + def find_method_named(name, ignore_case=nil) + if !ignore_case + @method_list.find {|meth| meth.name == name} + else + @method_list.find {|meth| meth.name.upcase == name.upcase} + end end # Find a named instance method, or return nil - def find_instance_method_named(name) - @method_list.find {|meth| meth.name == name && !meth.singleton} + def find_instance_method_named(name, ignore_case=nil) + if !ignore_case + @method_list.find {|meth| meth.name == name && !meth.singleton} + else + @method_list.find {|meth| + meth.name.upcase == name.upcase && !meth.singleton + } + end end # Find a named constant, or return nil - def find_constant_named(name) - @constants.find {|m| m.name == name} + def find_constant_named(name, ignore_case=nil) + if !ignore_case + @constants.find {|m| m.name == name} + else + @constants.find {|m| m.name.upcase == name.upcase} + end end # Find a named attribute, or return nil - def find_attribute_named(name) - @attributes.find {|m| m.name == name} + def find_attribute_named(name, ignore_case=nil) + if !ignore_case + @attributes.find {|m| m.name == name} + else + @attributes.find {|m| m.name.upcase == name.upcase} + end end - + end @@ -465,13 +535,15 @@ attr_accessor :file_relative_name attr_accessor :file_absolute_name attr_accessor :diagram - + @@all_classes = {} @@all_modules = {} + @@all_files = {} def TopLevel::reset @@all_classes = {} @@all_modules = {} + @@all_files = {} end def initialize(file_name) @@ -481,6 +553,7 @@ @file_absolute_name = file_name @file_stat = File.stat(file_name) @diagram = nil + @@all_files[file_name] = self end def full_name @@ -519,6 +592,10 @@ @@all_classes.values + @@all_modules.values end + def TopLevel.all_files + @@all_files + end + def TopLevel.find_class_named(name) @@all_classes.each_value do |c| res = c.find_class_named(name) @@ -527,21 +604,50 @@ nil end - def find_local_symbol(symbol) - find_class_or_module_named(symbol) || super + def find_local_symbol(symbol, ignore_case=nil) + find_class_or_module_named(symbol, ignore_case) || super end - def find_class_or_module_named(symbol) - @@all_classes.each_value {|c| return c if c.name == symbol} - @@all_modules.each_value {|m| return m if m.name == symbol} + def find_class_or_module_named(symbol, ignore_case=nil) + if !ignore_case + @@all_classes.each_value {|c| return c if c.name == symbol} + @@all_modules.each_value {|m| return m if m.name == symbol} + else + @@all_classes.each_value {|c| return c if c.name.upcase == symbol.upcase} + @@all_modules.each_value {|m| return m if m.name.upcase == symbol.upcase} + end nil end # Find a named module - def find_module_named(name) - find_class_or_module_named(name) || find_enclosing_module_named(name) + def find_module_named(name, ignore_case=nil) + find_class_or_module_named(name, ignore_case) || find_enclosing_module_named(name, ignore_case) end + # Find a named file + def find_file_named(name, method=nil, ignore_case=nil) + return nil unless name + result = nil + @@all_files.each{|file_name, toplevel| + result = toplevel if file_name == name + } + dir = File.dirname(@file_relative_name) + @@all_files.each{|file_name, toplevel| + if /^#{dir}\/(.*)/ =~ file_name + result = toplevel if $1 == name + end + } + if result + if method + result_method = result.find_local_symbol(method, ignore_case) + return result_method + else + return result + end + else + return nil + end + end end @@ -593,6 +699,11 @@ @classes.each_value {|c| return c if c.find_class_named(name) } nil end + + def find_file_named(name, method=nil, ignore_case=nil) + parent.find_file_named(name, method, ignore_case) + end + end # Anonymous classes @@ -648,7 +759,11 @@ end def <=>(other) - @name <=> other.name + t = @name <=> other.name + return t if t != 0 + t = @params <=> other.params + return t if t != 0 + t = @comment <=> other.comment end def to_s @@ -689,7 +804,7 @@ # with a particular context class Alias < CodeObject attr_accessor :text, :old_name, :new_name, :comment - + def initialize(text, old_name, new_name, comment) super() @text = text diff -Nur --exclude=doc ruby-1.8.3/lib/rdoc/diagram.rb ../rdoc-dennou-20051213/diagram.rb --- ruby-1.8.3/lib/rdoc/diagram.rb 2004-07-17 05:27:29.000000000 +0900 +++ ../rdoc-dennou-20051213/diagram.rb 2005-09-22 16:49:18.000000000 +0900 @@ -295,7 +295,7 @@ f << graph.to_s << "\n" end - system "dot -T#{op_type} #{src} -o #{dot}" + system "dot", "-T#{op_type}", src, "-o", dot # Now construct the imagemap wrapper around # that png diff -Nur --exclude=doc ruby-1.8.3/lib/rdoc/generators/chm_generator.rb ../rdoc-dennou-20051213/generators/chm_generator.rb --- ruby-1.8.3/lib/rdoc/generators/chm_generator.rb 2003-12-01 16:12:48.000000000 +0900 +++ ../rdoc-dennou-20051213/generators/chm_generator.rb 2005-09-22 16:49:18.000000000 +0900 @@ -4,7 +4,7 @@ class CHMGenerator < HTMLGenerator - HHC_PATH = "c:\\Program Files\\HTML Help Workshop\\hhc.exe" + HHC_PATH = "c:/Program Files/HTML Help Workshop/hhc.exe" # Standard generator factory def CHMGenerator.for(options) @@ -103,7 +103,7 @@ # Invoke the windows help compiler to compiler the project def compile_project - system("\"#{HHC_PATH}\" #@project_name") + system(HHC_PATH, @project_name) end end diff -Nur --exclude=doc ruby-1.8.3/lib/rdoc/generators/html_generator.rb ../rdoc-dennou-20051213/generators/html_generator.rb --- ruby-1.8.3/lib/rdoc/generators/html_generator.rb 2005-02-12 19:57:20.000000000 +0900 +++ ../rdoc-dennou-20051213/generators/html_generator.rb 2005-10-25 21:29:56.000000000 +0900 @@ -114,7 +114,12 @@ lookup = name end - if /([A-Z].*)[.\#](.*)/ =~ lookup + # Find class, module, or method in class or module. + if /([A-Z]\w*)[.\#](\w+[!?=]?)/ =~ lookup + container = $1 + method = $2 + ref = @context.find_symbol(container, method) + elsif /([A-Za-z]\w*)[.\#](\w+(\([\.\w+\*\/\+\-\=\<\>]+\))?)/ =~ lookup container = $1 method = $2 ref = @context.find_symbol(container, method) @@ -129,6 +134,30 @@ end end + # + # CROSSREFFILE is similar to CROSSREF. But this pattern is + # hit to filenames or methods in files + # + def handle_special_CROSSREFFILE(special) + name = special.text + + # Find file, or method in file + if /([\w\/].*\.\w+)[.\#](.*)/ =~ name + file_name = $1 + method = $2 + ref = @context.find_file(file_name, method) + else + ref = @context.find_file(name) + end + + if ref and ref.document_self + "#{name}" + else + name + end + + end + # Generate a hyperlink for url, labeled with text. Handle the # special cases for img: and link: described under handle_special_HYPEDLINK @@ -206,15 +235,24 @@ unless defined? @markup @markup = SM::SimpleMarkup.new - # class names, variable names, file names, or instance variables + # class names, variable names, or instance variables @markup.add_special(/( - \b([A-Z]\w*(::\w+)*[.\#]\w+) # A::B.meth + \w+(::\w+)*[.\#]\w+(\([\.\w+\*\/\+\-\=\<\>]+\))? # A::B.meth(**) (for operator in Fortran95) + | \#\w+(\([.\w\*\/\+\-\=\<\>]+\))? # meth(**) (for operator in Fortran95) + | \b([A-Z]\w*(::\w+)*[.\#]\w+) # A::B.meth | \b([A-Z]\w+(::\w+)*) # A::B.. | \#\w+[!?=]? # #meth_name - | \b\w+([_\/\.]+\w+)+[!?=]? # meth_name + | \b\w+([_\/\.]+\w+)*[!?=]? # meth_name )/x, :CROSSREF) + # file names + @markup.add_special(/( + [\w\/][\w\#\/\.\-\~\:]*[!?=]? # file_name + | [\w\/][\w\#\/\.\-\~\:]*(\([\.\w+\*\/\+\-\=\<\>]+\))? + )/x, + :CROSSREFFILE) + # external hyperlinks @markup.add_special(/((link:|https?:|mailto:|ftp:|www\.)\S+\w)/, :HYPERLINK) @@ -397,7 +435,8 @@ # end # end - ref = @context.find_symbol(i.name) + ref = @context.find_symbol(i.name, nil, @options.ignore_case) || \ + @context.find_file(i.name) ref = ref.viewer if ref if !ref && block_given? @@ -546,7 +585,17 @@ # Find a symbol in ourselves or our parent def find_symbol(symbol, method=nil) - res = @context.find_symbol(symbol, method) + res = @context.find_symbol(symbol, method, @options.ignore_case) + if res + res = res.viewer + end + res + end + + # Find a filenames in ourselves or our parent + def find_file(file, method=nil) + res = @context.find_file(file, method, + @options.ignore_case) if res res = res.viewer end @@ -1110,12 +1159,22 @@ end def find_symbol(symbol, method=nil) - res = @context.parent.find_symbol(symbol, method) + res = @context.parent.find_symbol(symbol, method, @options.ignore_case) + if res + res = res.viewer + end + res + end + + # Find a filenames in ourselves or our parent + def find_file(file, method=nil) + res = @context.parent.find_file(file, method) if res res = res.viewer end res end + end ##################################################################### diff -Nur --exclude=doc ruby-1.8.3/lib/rdoc/install.rb ../rdoc-dennou-20051213/install.rb --- ruby-1.8.3/lib/rdoc/install.rb 1970-01-01 09:00:00.000000000 +0900 +++ ../rdoc-dennou-20051213/install.rb 2005-11-15 19:46:25.000000000 +0900 @@ -0,0 +1,174 @@ +require 'rbconfig' +require 'find' +require 'ftools' +require 'optparse' + +include Config + +$ruby = CONFIG['ruby_install_name'] + +## +# Install a binary file. We patch in on the way through to +# insert a #! line. If this is a Unix install, we name +# the command (for example) 'rdoc' and let the shebang line +# handle running it. Under windows, we add a '.rb' extension +# and let file associations to their stuff +# + +def installBIN(from, opfile) + + tmp_dir = nil + for t in [".", "/tmp", "c:/temp", $bindir] + stat = File.stat(t) rescue next + if stat.directory? and stat.writable? + tmp_dir = t + break + end + end + + fail "Cannot find a temporary directory" unless tmp_dir + tmp_file = File.join(tmp_dir, "_tmp") + + + File.open(from) do |ip| + File.open(tmp_file, "w") do |op| + ruby = File.join($realbindir, $ruby) +# op.puts "#!#{ruby}" + op.write ip.read + end + end + + opfile += ".rb" if CONFIG["target_os"] =~ /mswin/i + File::install(tmp_file, File.join($bindir, opfile), 0755, true) + File::unlink(tmp_file) +end + +# Main Program + +opt = OptionParser.new +OPTS = {} +opt.on('--help') {|v| OPTS[:help] = v} +opt.on('--bindir=VAL', + 'Directory to which the libraries are installed') \ + {|v| $bindir = v.to_s} +opt.on('--libdir=VAL', + 'Directory to which the executable file "rdoc" is installed') \ + {|v| $libdir = v.to_s} + +opt.parse!(ARGV) + +$bindir = File.expand_path($bindir) if $bindir +$libdir = File.expand_path($libdir) if $libdir + +install_opt = "" +install_opt = "--libdir=#{$libdir}" if $libdir + +if $libdir + $sitedir = $libdir +else + $sitedir = CONFIG["sitelibdir"] + unless $sitedir + version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"] + $libdir = File.join(CONFIG["libdir"], "ruby", version) + $sitedir = $:.find {|x| x =~ /site_ruby/} + if !$sitedir + $sitedir = File.join($libdir, "site_ruby") + elsif $sitedir !~ Regexp.quote(version) + $sitedir = File.join($sitedir, version) + end + end +end + +$bindir ||= CONFIG["bindir"] +$realbindir = $bindir + +bindir = CONFIG["bindir"] + +rdoc_dest = File.join($sitedir, "rdoc") +dot_dest = File.join(rdoc_dest, "dot") +rdoc_generators = File.join(rdoc_dest, "generators") +rdoc_templates = File.join(rdoc_generators, "template") +rdoc_parsers = File.join(rdoc_dest, "parsers") +rdoc_ri = File.join(rdoc_dest, "ri") + +# help message +if ARGV[0] || OPTS[:help] + print <<-HELP + + This ruby script installs libraries to \"#{rdoc_dest}\", + and executables to \"#{$bindir}\". (See \"rbconfig.rb\") + + If you want to install other directory, use following options. + + OPTIONS: + + --libdir Directory to which the libraries are installed + --bindir Directory to which the executable file "rdoc" is installed + +HELP + exit +end + +# make directories +File::makedirs(rdoc_dest, + dot_dest, + rdoc_generators, + rdoc_templates, + rdoc_parsers, + rdoc_ri, + true) + +File::chmod(0755, rdoc_dest) + + + +# The library files +files = %w{ + code_objects.rb + generators/*_generator.rb + options.rb + parsers/parserfactory.rb + parsers/parse_*.rb + template.rb + tokenstream.rb + diagram.rb + rdoc.rb + dot/dot.rb + ri/ri_*.rb +}.collect {|f| Dir.glob(f)}.flatten + +for template in ["chm", "html", "xml"] + File::makedirs(File.join(rdoc_templates, template), true) + files.concat Dir.glob("rdoc/generators/template/#{template}/*.rb") +end + +for aFile in files + File::install(aFile, File.join(rdoc_dest, aFile), 0644, true) +end + +# and the executable + +installBIN("rdoc", "rdoc") + +# Temporary - we used to install html_generator in the rdoc +# directory, but now it's moved + +File.unlink(File.join(rdoc_dest, "html_generator.rb")) rescue 1; + +# and we used to have the templates under html_template +template = File.join(rdoc_dest, "generators", "html_template") +File.unlink(File.join(template, "standard.rb")) rescue 1; +File.unlink(File.join(template, "kilmer.rb")) rescue 1; + +# and then they were in template/ ... +template = File.join(rdoc_dest, "generators", "template") +File.unlink(File.join(template, "standard.rb")) rescue 1; +File.unlink(File.join(template, "kilmer.rb")) rescue 1; +File.unlink(File.join(template, "xml.rb")) rescue 1; +File.unlink(File.join(template, "rdf.rb")) rescue 1; + + +# 'Markup' will eventually be a separate package, but +# for now we'll install it automatically + +Dir.chdir("markup") && system("#$ruby install.rb #{install_opt}") diff -Nur --exclude=doc ruby-1.8.3/lib/rdoc/markup/install.rb ../rdoc-dennou-20051213/markup/install.rb --- ruby-1.8.3/lib/rdoc/markup/install.rb 1970-01-01 09:00:00.000000000 +0900 +++ ../rdoc-dennou-20051213/markup/install.rb 2005-11-15 19:46:27.000000000 +0900 @@ -0,0 +1,58 @@ +require 'rbconfig' +require 'find' +require 'ftools' +require 'optparse' + +include Config + +opt = OptionParser.new +libdir = nil +opt.on('--libdir=VAL') {|v| libdir = v} +opt.parse!(ARGV) + +libdir = File.expand_path(libdir) if libdir + +if libdir + sitedir = libdir +else + sitedir = CONFIG["sitelibdir"] + unless sitedir + version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"] + libdir = File.join(CONFIG["libdir"], "ruby", version) + sitedir = $:.find {|x| x =~ /site_ruby/} + if !sitedir + sitedir = File.join(libdir, "site_ruby") + elsif sitedir !~ Regexp.quote(version) + sitedir = File.join(sitedir, version) + end + end +end + +unless /^\// =~ sitedir.strip + sitedir = File.join("..", sitedir) +end + +if !File.directory?(sitedir) + $stderr.puts "Cannot find sitedir #{sitedir}" + exit 1 +end + +rdoc_dest = File.join(sitedir, "rdoc") + +dest = File.join(rdoc_dest, "markup") + +File.mkpath(dest, true) + +Find.find("simple_markup.rb", + "simple_markup", + "sample", + "test") do |fname| + if File.directory?(fname) + next if fname =~ /CVS/ + File.mkpath(File.join(dest, fname), true) + else + next unless fname =~ /\.rb$/ + next if fname =~ /install.rb$/ + File.install(fname, File.join(dest, fname), 0444, true) + end +end diff -Nur --exclude=doc ruby-1.8.3/lib/rdoc/markup/simple_markup/preprocess.rb ../rdoc-dennou-20051213/markup/simple_markup/preprocess.rb --- ruby-1.8.3/lib/rdoc/markup/simple_markup/preprocess.rb 2004-11-26 13:32:11.000000000 +0900 +++ ../rdoc-dennou-20051213/markup/simple_markup/preprocess.rb 2005-09-22 16:49:19.000000000 +0900 @@ -43,7 +43,12 @@ def include_file(name, indent) if (full_name = find_include_file(name)) content = File.open(full_name) {|f| f.read} - res = content.gsub(/^#?/, indent) + # strip leading '#'s, but only if all lines start with them + if content =~ /^[^#]/ + content.gsub(/^/, indent) + else + content.gsub(/^#?/, indent) + end else $stderr.puts "Couldn't find file to include: '#{name}'" '' diff -Nur --exclude=doc ruby-1.8.3/lib/rdoc/markup/simple_markup.rb ../rdoc-dennou-20051213/markup/simple_markup.rb --- ruby-1.8.3/lib/rdoc/markup/simple_markup.rb 2004-04-24 10:39:45.000000000 +0900 +++ ../rdoc-dennou-20051213/markup/simple_markup.rb 2005-10-30 19:46:32.000000000 +0900 @@ -194,8 +194,7 @@ LABEL_LIST_RE = /^( ( \[.*?\] (?# labeled ) |\S.*:: (?# note ) - )(?=\s|$) - \s* + )(?:\s+|$) )/x diff -Nur --exclude=doc ruby-1.8.3/lib/rdoc/options.rb ../rdoc-dennou-20051213/options.rb --- ruby-1.8.3/lib/rdoc/options.rb 2004-11-21 00:02:56.000000000 +0900 +++ ../rdoc-dennou-20051213/options.rb 2005-10-06 17:55:59.000000000 +0900 @@ -91,6 +91,9 @@ # multiple files attr_reader :promiscuous + # The case of names of classes or modules or methods are ignored + attr_reader :ignore_case + module OptionList OPTION_LIST = [ @@ -143,6 +146,10 @@ [ "--help-output", "-O", nil, "explain the various output options" ], + [ "--ignore-case", "-C", nil, + "The case of names of classes or modules\n" + + "or methods are ignored" ], + [ "--image-format", "-I", "gif/png/jpg/jpeg", "Sets output image format for diagrams. Can\n" + "be png, gif, jpeg, jpg. If this option is\n" + @@ -363,6 +370,7 @@ @include_line_numbers = false @extra_accessor_flags = {} @promiscuous = false + @ignore_case = false @css = nil @webcvs = nil @@ -401,6 +409,7 @@ when "--template" then @template = arg when "--title" then @title = arg when "--webcvs" then @webcvs = arg + when "--ignore-case" then @ignore_case = true when "--accessor" arg.split(/,/).each do |accessor| diff -Nur --exclude=doc ruby-1.8.3/lib/rdoc/parsers/parse_c.rb ../rdoc-dennou-20051213/parsers/parse_c.rb --- ruby-1.8.3/lib/rdoc/parsers/parse_c.rb 2005-07-16 00:00:11.000000000 +0900 +++ ../rdoc-dennou-20051213/parsers/parse_c.rb 2005-09-22 21:30:56.000000000 +0900 @@ -167,7 +167,7 @@ extend ParserFactory - parse_files_matching(/\.(c|cc|cpp|CC)$/) + parse_files_matching(/\.(c|cc|cpp|CC|cxx)$/) @@known_bodies = {} diff -Nur --exclude=doc ruby-1.8.3/lib/rdoc/parsers/parse_f95.rb ../rdoc-dennou-20051213/parsers/parse_f95.rb --- ruby-1.8.3/lib/rdoc/parsers/parse_f95.rb 2004-01-02 15:01:12.000000000 +0900 +++ ../rdoc-dennou-20051213/parsers/parse_f95.rb 2005-12-13 14:24:24.000000000 +0900 @@ -1,15 +1,418 @@ -# Parse a Fortran 95 file. +#= parse_f95.rb - Fortran95 Parser +# +#== 概要 +# +#parse_f95.rb は拡張子が f90, F90, f95, F95 のファイルを構文分析します. +#ソースコードは Fortran 95 規格で推奨される書法で記述されることを +#前提としています. +# +#== Overview +# +#"parse_f95.rb" parses Fortran95 files with suffixes "f90", "F90", "f95" +#and "F95". Fortran95 files are expected to be conformed to Fortran95 +#standards. +# +#== 書法 +# +#基本的な書法は{Ruby の書法}[http://www.ruby-doc.org/stdlib/libdoc/rdoc/rdoc/index.html] +#と同様ですが, コメント部は '#' ではなく '!' で始まることに注意してください. +# +#== Rules +# +#Fundamental rules are same as that of the Ruby parser. +#But comment markers are '!' not '#'. +# +#=== RDoc ドキュメンテーションと Fortran95 プログラムとの対応 +# +#parse_f95.rb はメインプログラム, モジュール, サブルーチン, 関数の他, +#public 指定によって公開される変数や定数, そして利用者定義演算子, +#利用者定義代入を構文分析します. +#これらの要素は RDOC ドキュメンテーションの各項目に, +#以下のように記述されます. +# +#Files :: ファイル (Ruby と同様です) +#Classes :: モジュール +#Methods :: サブルーチン, 関数, 変数, 定数, 構造体, 利用者定義演算子, 利用者定義代入 +#Required files :: 参照するモジュールが定義されているファイル, 及び参照する外部関数が定義されているファイルのリスト +#Included Modules :: 参照するモジュールのリスト +#Attributes :: 構造体のリスト, 参照し且つその全ての要素を公開するモジュールのリスト +# +#'Methods' にリストされる要素 (サブルーチン, 関数, …) は, +#モジュール内で定義されているのであれば, 'Classes' の項目に記述されます. +#メインプログラム内で定義されたり, 外部手続きとして定義される場合には +#'Files' の項目に記述されます. +# +# +#=== Correspondence between RDoc documentation and Fortran95 programs +# +#"parse_f95.rb" parses main programs, modules, subroutines, functions, +#derived-types, public variables, public constants, +#defined operators and defined assignments. +#These components are described in items of RDoc documentation, as follows. +# +#Files :: Files (same as Ruby) +#Classes :: Modules +#Methods :: Subroutines, functions, variables, constants, derived-types, defined operators, defined assignments +#Required files :: Files in which imported modules, external subroutines and external functions are defined. +#Included Modules :: List of imported modules +#Attributes :: List of derived-types, List of imported modules all of whose components are published again +# +#Components listed in 'Methods' (subroutines, functions, ...) +#defined in modules are described in the item of 'Classes'. +#On the other hand, components defined in main programs or +#as external procedures are described in the item of 'Files'. +# +#=== デフォルトで構文分析される要素 +# +#デフォルトでは, public 属性を持ち, 外部から参照が可能なサブルーチン, +#関数, 変数, 定数, 構造体, 利用者定義演算子, +#利用者定義代入のみドキュメントとして出力されます. --all +#オプションをつけて rdoc を実行する場合には private 属性を +#明示的に指定されるものも含め, 全てが出力されます. +# +# +#=== Components parsed by default +# +#By default, documentation on public components (subroutines, functions, +#variables, constants, derived-types, defined operators, +#defined assignments) are generated. +#With "--all" option, documentation on all components +#are generated (almost same as the Ruby parser). +# +# +#=== 自動的に構文分析される情報 +# +#以下の情報は, 自動的に構文分析されてコメント部として出力されます. +# +#* サブルーチン, 関数の引数の型 +#* 公開変数, 公開定数の自身の型 +#* 構造体の要素の型, 初期値 +#* NAMELIST 変数とその要素の型, 初期値 +# +#interface によって別名を指定する場合, その別名も 'Methods' に +#追加します. +# +#参照した別のモジュール内の公開要素 (サブルーチン, 関数, …) +#を自身の要素として改めて公開する場合, +#その要素は自身の要素としてモジュールの 'Methods' リストに追加されます. +# +#interface によって外部副プログラムを自身の副プログラムとして公開する +#場合, その外部副プログラムもモジュールの 'Methods' リストに追加します. +# +# +#=== Information parsed automatically +# +#The following information is automatically parsed. +# +#* Types of arguments +#* Types of variables and constants +#* Types of variables in the derived types, and initial values +#* NAMELISTs and types of variables in them, and initial values +# +#Aliases by interface statement are described in the item of 'Methods'. +# +#Components which are imported from other modules and published again +#are described in the item of 'Methods'. +# +# +#=== コメント部の書き方 +# +#コメント部は以下のように記述します. 原則的に行末または Fortran +#の文の下部にコメントを記述します. '!' を含まない行が現れた時点で, +#コメント部は終了したと見なされます. +#例ではコメント行もインデントされていますが, インデントすることは +#必須ではありません. +# +# ! (ファイルの行頭) +# ! +# ! ファイルに対するコメントはここに記述します +# ! +# module hogehoge +# ! +# ! モジュール (program の場合はメインルーチン) +# ! に対するコメントはここに記述します +# ! +# +# private +# +# logical :: a ! 非公開変数 +# real, public :: b ! 公開変数 +# integer, parameter :: c = 0 ! 公開定数 +# +# public :: c +# public :: MULTI_ARRAY +# public :: hoge, foo +# +# type MULTI_ARRAY +# ! +# ! 構造体に対するコメントはここに記述します. +# ! +# real, pointer :: var(:) =>null() ! 変数に対するコメント +# integer :: num = 0 +# end type MULTI_ARRAY +# +# contains +# +# subroutine hoge( in, & ! 継続行中のコメントは無視されます. +# & out ) +# ! +# ! サブルーチンや関数に対するコメントはここに記述します +# ! +# character(*),intent(in):: in ! 引数に対するコメント +# character(*),intent(out),allocatable,target :: in +# ! 下の行に記述する +# ! ことも可能です. +# +# character(32) :: file ! NAMELIST 内の変数として構文分析されます +# integer :: id +# +# namelist /varinfo_nml/ file, id +# ! +# ! NAMELIST に関する情報はここに記述します. 変数に +# ! 関する情報は, 変数定義部分を参照します. +# ! +# +# .... +# +# end subroutine hoge +# +# integer function foo( in ) +# ! +# ! この部分はコメントとして識別されます. +# +# ! '!' の間隔を空けると以降はコメントとして扱われません. +# ! つまりこの 2 行はコメントとして扱われません. +# ! +# integer, intent(in):: inA ! コメントとして識別されます +# +# ! コメントとして識別されません. +# +# end function foo +# +# subroutine hide( in, & +# & out ) !:nodoc: +# ! +# ! 上記のように, subroutine 文の末尾に +# ! "!:nodoc:" と記述することで, そのサブルーチン +# ! はドキュメントに反映されなくなります. +# ! この指定は, モジュール, サブルーチン, 関数, 変数, 定数, +# ! 構造体, 利用者定義演算子, 利用者定義代入, +# ! 参照するモジュールのリスト (use 文) に対して有効です. +# ! +# +# .... +# +# end subroutine hide +# +# end module hogehoge +# +#=== Format of comment blocks +# +#Comment blocks should be written as follows. +#Comment blocks are considered to be ended when the line without '!' +#appears. +#The indentation is not necessary. +# +# ! (Top of file) +# ! +# ! Comment blocks for the files. +# ! +# module hogehoge +# ! +# ! Comment blocks for the modules (or the programs). +# ! +# +# private +# +# logical :: a ! a private variable +# real, public :: b ! a public variable +# integer, parameter :: c = 0 ! a public constant +# +# public :: c +# public :: MULTI_ARRAY +# public :: hoge, foo +# +# type MULTI_ARRAY +# ! +# ! Comment blocks for the derived-types. +# ! +# real, pointer :: var(:) =>null() ! Comments block for the variables. +# integer :: num = 0 +# end type MULTI_ARRAY +# +# contains +# +# subroutine hoge( in, & ! Comment blocks between continuation lines are ignored. +# & out ) +# ! +# ! Comment blocks for the subroutines or functions +# ! +# character(*),intent(in):: in ! Comment blocks for the arguments. +# character(*),intent(out),allocatable,target :: in +# ! Comment blocks can be +# ! written under Fortran statements. +# +# character(32) :: file ! This comment parsed as a variable in below NAMELIST. +# integer :: id +# +# namelist /varinfo_nml/ file, id +# ! +# ! Comment blocks for the NAMELISTs. +# ! Information about variables are described above. +# ! +# +# .... +# +# end subroutine hoge +# +# integer function foo( in ) +# ! +# ! This part is considered as comment block. +# +# ! Comment blocks under blank lines are ignored. +# ! +# integer, intent(in):: inA ! This part is considered as comment block. +# +# ! This part is ignored. +# +# end function foo +# +# subroutine hide( in, & +# & out ) !:nodoc: +# ! +# ! If "!:nodoc:" is described at end-of-line in subroutine +# ! statement as above, the subroutine is ignored. +# ! This assignment can be used to modules, subroutines, +# ! functions, variables, constants, derived-types, +# ! defined operators, defined assignments, +# ! list of imported modules ("use" statement). +# ! +# +# .... +# +# end subroutine hide +# +# end module hogehoge +# +#=== 注意 +# +# parse_f95.rb は出来るだけ Fortran90/95 規格に準拠してソースコードを +# 解析しようとしていますが, 以下の記述に対しての解析はまだ不十分です. +# 利用の際には御注意ください. +# +# * end 文 +# +# program, module, subroutine, function の end 文は必ず +# end program, end module, end subroutine, end function のように +# 記述してください. Fortran90/95 規格 では end の後ろを省略することが +# 可能ですが, 現在の parse_f95.rb ではその書法を正しく解析出来ません. +# +# * program 文 +# +# parse_f95.rb では program 文の内部で定義される定数や変数, 関数, +# サブルーチンは private なものとして解釈します. しかし +# program 〜 end program 文の, 最初と最後の program という文字を +# 省略した場合, program 文の内部で定義されるものは全て public だと +# 認識されます. +# +# +#=== Cautions +# +# Parse_f95.rb analyzes the source code as much as possible in +# accordance with the Fortran90/95 standard. +# However, a correct analysis cannot be done for the following points yet. +# +# * end statement +# +# If "end program" is omitted to "end", correct analysis cannot be done. +# This applies for not only "end program" but also "end module", +# "end subroutine" and "end function". +# +# * program statement +# +# If "program" statement is omitted, components defined in main programs +# are treated as public (originally, they are private). +# +#-- +# +#== 今後の改良予定 +# +#* end の後ろを省略された場合でも解釈できるよう修正. +# (面倒だが結構重要な気がするなぁ…) +# +# ただしその場合はこれまでの解析方法を結構変更する必要がある. +# 今までは while 文で解析を行ってきたがそれを廃し, 解析用の +# メソッドを別途準備する必要が出てくる. 解析の方法としては +# やっぱり上から下までぜーんぶ読む方法しかなく, +# 例えば moudule や program の解析の際には内部の subroutine や +# function の "end" で終了するわけにはいかないので, +# subroutine や function, block data などの開始ステートメントを +# チェックし, end との差し引きでチェックする必要がある. +# +# …書いてみたらたいしたものでも無い気がしてきたなぁ... +# +#* program が省略される場合の対応 +# (優先順位ちょっと低い) +# +# 上から読み込んで行き, module, subroutine, function, 空行 +# コメント行以外である場合はメインプログラムであると識別すればよい. +# +#* モジュール本体に定義された NAMELIST を構文分析する. +# * 定義されたところで出力するか, 入力される場所 (正規表現ならば +# read\s*\(.*nml=\s* で取得可能なはず) +# で書き出すかはちょっと問題. たぶん書き出すところに +# 書いておくのが便利だと思う. (NAMELIST は公開要素に出来ないし) +# +#* NAMELIST もメソッド名として出力する. +# * 1つの NAMELIST に対して出力先を 2 つ用意する +# 1. そのモジュールまたはプログラム本体に出力. 実際にどのサブルーチン +# または関数で read されるのかはそれだけでは分からないため, +# どこで read されるかは解析し, コメントとして出力する +# 2. "NAMELIST" というモジュールをその場で定義し, その中のメソッドとして +# 上記の情報を書き出す. この場合, 「どのモジュールまたはメイン +# プログラム」で呼ばれるか分からないため, それに関しても +# コメントに書き出す. 結果, 複数のファイル内において定義される +# "NAMELIST" という "Classes" に解析した全ての NAMELIST が書き出される +# ことになる. +# +#* 構造体, 変数, 定数の時にメソッドの横に出力される無駄な "( )" を消す. +# html_generator に手を入れれば意外と簡単に処理できるはず. +# * 具体案1 +# * :nobracket というシンボルを指定した場合は完全に空白のみ出力する. +# +#* ";" を改行と認識するようになっているが, 文字列として使われて +# いる場合 (";" などとなる場合) を見分けるようにしておく. +# +# これも行頭からチェックし, シングルクオーテーション, +# ダブルクオーテーションの数でチェックすればどうとでもなるかな? +# 括弧は必要ないなぁ…. +# +#* 行末の & を継続行と認識するようになっているが, 文字列として使われて +# いる場合 ("& ! " などとなる場合) を見分けるようにしておく. +# +# これも行頭からチェックし, シングルクオーテーション, +# ダブルクオーテーションの数でチェックすればどうとでもなるかな? +# 括弧は必要ないなぁ…. +# +#* メインプログラム中の NAMELIST が private に入っているので見えないのは +# 不便なため, NAMELIST だけは見えるようにするなどの処置が必要 +# +#* メインプログラムで下位の NAMELIST のリストを全部探査し, それらを +# 表示できるようにしておくと良いだろう. +# * "== NAEMLIST" などと書いてある場合のみ, それらがコメント部に +# 現れるようにしておくのが良いと考えられる. +# +#++ + require "rdoc/code_objects" module RDoc - # See rdoc/parsers/parse_f95.rb - class Token NO_TEXT = "??".freeze - + def initialize(line_no, char_no) @line_no = line_no @char_no = char_no @@ -26,84 +429,919 @@ end + # See rdoc/parsers/parse_f95.rb + class Fortran95parser extend ParserFactory - parse_files_matching(/\.(f9(0|5)|F)$/) - + parse_files_matching(/\.((f|F)9(0|5)|F)$/) + + @@external_aliases = [] + @@public_methods = [] + + # "false":: Comments are below source code + # "true" :: Comments are upper source code + COMMENTS_ARE_UPPER = false + + # Internal alias message + INTERNAL_ALIAS_MES = "Alias for" + + # External alias message + EXTERNAL_ALIAS_MES = "The entity is" + # prepare to parse a Fortran 95 file def initialize(top_level, file_name, body, options, stats) @body = body @stats = stats + @file_name = file_name @options = options @top_level = top_level @progress = $stderr unless options.quiet end - + # devine code constructs def scan - # modules and programs - if @body =~ /^(module|program)\s+(\w+)/i - progress "m" - f9x_module = @top_level.add_module NormalClass, $2 - f9x_module.record_location @top_level - first_comment, second_comment = $`.gsub(/^!\s?/,"").split "\n\s*\n" - if second_comment - @top_level.comment = first_comment if first_comment - f9x_module.comment = second_comment - else - f9x_module.comment = first_comment if first_comment - end - end - - # use modules - remaining_code = @body - while remaining_code =~ /^\s*use\s+(\w+)/i - remaining_code = $~.post_match - progress "." - f9x_module.add_include Include.new($1, "") if f9x_module - end - - # subroutines - remaining_code = @body - while remaining_code =~ /^\s*subroutine\s+(\w+)\s*\((.*?)\)/im - remaining_code = $~.post_match - subroutine = AnyMethod.new("Text", $1) - subroutine.singleton = false - - prematchText = $~.pre_match - params = $2 - params.gsub!(/&/,'') - subroutine.params = params - comment = find_comments prematchText - subroutine.comment = comment if comment - - subroutine.start_collecting_tokens - remaining_code =~ /^\s*end\s+subroutine/i - code = "subroutine #{subroutine.name} (#{subroutine.params})\n" - code += $~.pre_match - code += "\nend subroutine\n" - subroutine.add_token Token.new(1,1).set_text(code) - - progress "s" - f9x_module.add_method subroutine if f9x_module + # remove private comment + remaining_code = remove_private_comments(@body) + + # continuation lines are united to one line + remaining_code = united_to_one_line(remaining_code) + + # collect comment for file entity + whole_comment, remaining_code = collect_first_comment(remaining_code) + @top_level.comment = whole_comment + + # "module" parts are parsed + # + while remaining_code =~ /^\s*?module\s+(\w+)\s*?(!.*?)?$(.*?)^\s*?end\s+module.*?$/im + remaining_code = $~.pre_match + remaining_code << $~.post_match + module_code = remove_empty_head_lines($&) + module_name = $1 + f9x_trailing = find_comments($2) + next if f9x_trailing =~ /^:nodoc:/ + progress "m" + @stats.num_modules += 1 + f9x_module = @top_level.add_module NormalClass, module_name + f9x_module.record_location @top_level + + f9x_comment = COMMENTS_ARE_UPPER ? + find_comments($~.pre_match) + "\n" + f9x_trailing : + f9x_trailing + "\n" + find_comments(module_code.sub(/^.*$\n/i, '')) + f9x_module.comment = f9x_comment + parse_program_or_module(f9x_module, module_code) + + TopLevel.all_files.each do |name, toplevel| + if toplevel.include_includes?(module_name, @options.ignore_case) + if !toplevel.include_requires?(@file_name, @options.ignore_case) + toplevel.add_require(Require.new(@file_name, "")) + end + end + toplevel.each_classmodule{|m| + if m.include_includes?(module_name, @options.ignore_case) + if !m.include_requires?(@file_name, @options.ignore_case) + m.add_require(Require.new(@file_name, "")) + end + end + } + end + end + + # "program" parts are parsed + # + # contains 以下の内部サブルーチンが存在するなど, + # サブプログラムの集まりとは少々違うため. + # + while remaining_code =~ /^\s*?program\s+(\w+)\s*?(!.*?)?$(.*?)^\s*?end\s+program.*?$/im + remaining_code = $~.pre_match + remaining_code << $~.post_match + program_code = remove_empty_head_lines($&) + progress "p" + program_name = $1 + program_trailing = find_comments($2) + program_comment = COMMENTS_ARE_UPPER ? + find_comments($~.pre_match) + "\n" + program_trailing : + program_trailing + "\n" + find_comments(program_code.sub(/^.*$\n/i, '')) + program_comment = "\n\n= Program #{program_name}\n\n" \ + + program_comment + @top_level.comment << program_comment + parse_program_or_module(@top_level, program_code, :private) end + # External subprograms and functions are parsed + # + # 単一のファイル内において program や module に格納されない, + # 外部サブルーチン, 外部関数部分の解析. + # + parse_program_or_module(@top_level, remaining_code, :public, true) + @top_level + end # End of scan + + private + + def parse_program_or_module(container, code, + visibility=:public, external=nil) + return unless container + return unless code + + remaining_code = "#{code}" + + # + # Parse variables before "contains" in module + # + # namelist 変数の定義に使われたり, これ自体が定数, 変数 + # 提供されるのに利用される. (変数や定数として利用される場合, + # これもメソッドとして提供する. + # + before_contains_code = nil + if remaining_code =~ / + ^\s*?module\s+\w+\s*?(!.*?)?$ + (.*?) + ^\s*?contains\s*?(!.*?)?$ + (.*?) + ^\s*?end\s+module.*?$ + /imx + before_contains_code = $2 + end + if remaining_code =~ + /^\s*?module\s+(\w+)\s*?$(.*?)^\s*?end\s+module.*?$/im && + !before_contains_code + before_contains_code = "#{remaining_code}" + end + if before_contains_code + before_contains_code.gsub!(/^\s*?interface\s+.*?\s+end\s+interface.*?$/im, "") + before_contains_code.gsub!(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "") + end + + # + # Parse global "use" + # + use_check_code = "#{before_contains_code}" + cascaded_modules_list = [] + while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i + use_check_code = $~.pre_match + use_check_code << $~.post_match + used_mod_name = $1.strip.chomp + used_list = $2 || "" + used_trailing = $3 || "" + next if used_trailing =~ /!:nodoc:/ + if !container.include_includes?(used_mod_name, @options.ignore_case) + progress "." + container.add_include Include.new(used_mod_name, "") + end + if ! (used_list =~ /\,\s*?only\s*?:/i ) + cascaded_modules_list << "\#" + used_mod_name + end + end + + # + # Parse public and private, and store information. + # This information is used when "add_method" and + # "set_visibility_for" are called. + # + visibility_default, visibility_info = + parse_visibility(remaining_code, visibility, container) + @@public_methods.concat visibility_info + + if visibility_default == :public + if !cascaded_modules_list.empty? + cascaded_modules = + Attr.new("Cascaded Modules", + "Imported modules all of whose components are published again", + "", + cascaded_modules_list.join(", ")) + container.add_attribute(cascaded_modules) + end + end + + # + # Check rename elements + # + use_check_code = "#{before_contains_code}" + while use_check_code =~ /^\s*?use\s+(\w+)\s*?\,(.+)$/i + use_check_code = $~.pre_match + use_check_code << $~.post_match + used_mod_name = $1.strip.chomp + used_elements = $2.sub(/\s*?only\s*?:\s*?/i, '') + used_elements.split(",").each{ |used| + if /\s*?(\w+)\s*?=>\s*?(\w+)\s*?/ =~ used + local = $1 + org = $2 + @@public_methods.collect!{ |pub_meth| + if local == pub_meth["name"] || + local.upcase == pub_meth["name"].upcase && + @options.ignore_case + pub_meth["name"] = org + pub_meth["local_name"] = local + end + pub_meth + } + end + } + end + + # + # Parse private "use" + # + use_check_code = "#{remaining_code}" + while use_check_code =~ /^\s*?use\s+(\w+)(.*?)(!.*?)?$/i + use_check_code = $~.pre_match + use_check_code << $~.post_match + used_mod_name = $1.strip.chomp + used_trailing = $3 || "" + next if used_trailing =~ /!:nodoc:/ + if !container.include_includes?(used_mod_name, @options.ignore_case) + progress "." + container.add_include Include.new(used_mod_name, "") + end + end + + container.each_includes{ |inc| + TopLevel.all_files.each do |name, toplevel| + indicated_mod = toplevel.find_symbol(inc.name, + nil, @options.ignore_case) + if indicated_mod + indicated_name = indicated_mod.parent.file_relative_name + if !container.include_requires?(indicated_name, @options.ignore_case) + container.add_require(Require.new(indicated_name, "")) + end + break + end + end + } + + # + # Parse derived-types definitions + # + derived_types_comment = "" + while remaining_code =~ /^\s*? + type[\s\,]+(public|private)?\s*?(::)?\s*? + (\w+)\s*?(!.*?)?$ + (.*?) + ^\s*?end\s+type.*?$ + /imx + remaining_code = $~.pre_match + remaining_code << $~.post_match + typename = $3.chomp.strip + type_elements = $5 || "" + type_code = remove_empty_head_lines($&) + type_trailing = find_comments($4) + next if type_trailing =~ /^:nodoc:/ + type_visibility = $1 + type_comment = COMMENTS_ARE_UPPER ? + find_comments($~.pre_match) + "\n" + type_trailing : + type_trailing + "\n" + find_comments(type_code.sub(/^.*$\n/i, '')) + type_element_visibility_public = true + type_code.split("\n").each{ |line| + if /^\s*?private\s*?$/ =~ line + type_element_visibility_public = nil + break + end + } if type_code + + args_comment = "" + type_args_info = nil + + if @options.show_all + args_comment = find_arguments(nil, type_code, true) + else + type_public_args_list = [] + type_args_info = definition_info(type_code) + type_args_info.each{ |arg| + arg_is_public = type_element_visibility_public + arg_is_public = true if arg.include_attr?("public") + arg_is_public = nil if arg.include_attr?("private") + type_public_args_list << arg.varname if arg_is_public + } + args_comment = find_arguments(type_public_args_list, type_code) + end + + type = AnyMethod.new("type #{typename}", typename) + type.singleton = false + type.params = "" + type.comment = " Derived Type :: \n" + type.comment << args_comment if args_comment + type.comment << type_comment if type_comment + progress "t" + @stats.num_methods += 1 + container.add_method type + + set_visibility(container, typename, visibility_default, @@public_methods) + + if type_visibility + type_visibility.gsub!(/\s/,'') + type_visibility.gsub!(/\,/,'') + type_visibility.gsub!(/:/,'') + type_visibility.downcase! + if type_visibility == "public" + container.set_visibility_for([typename], :public) + elsif type_visibility == "private" + container.set_visibility_for([typename], :private) + end + end + + check_public_methods(type, container.name) + + if @options.show_all + derived_types_comment << ", " unless derived_types_comment.empty? + derived_types_comment << typename + else + if type.visibility == :public + derived_types_comment << ", " unless derived_types_comment.empty? + derived_types_comment << typename + end + end + + end + + if !derived_types_comment.empty? + derived_types_table = + Attr.new("Derived Types", "Derived_Types", "", + derived_types_comment) + container.add_attribute(derived_types_table) + end + + # + # move interface scope + # + interface_code = "" + while remaining_code =~ /^\s*? + interface( + \s+\w+ | + \s+operator\s*?\(.*?\) | + \s+assignment\s*?\(\s*?=\s*?\) + )?\s*?$ + (.*?) + ^\s*?end\s+interface.*?$ + /imx + interface_code << remove_empty_head_lines($&) + "\n" + remaining_code = $~.pre_match + remaining_code << $~.post_match + end + + # + # Parse global constants or variables in modules + # + const_var_defs = definition_info(before_contains_code) + const_var_defs.each{|defitem| + next if defitem.nodoc + const_or_var_type = "Variable" + const_or_var_progress = "v" + if defitem.include_attr?("parameter") + const_or_var_type = "Constant" + const_or_var_progress = "c" + end + const_or_var = AnyMethod.new(const_or_var_type, defitem.varname) + const_or_var.singleton = false + const_or_var.params = "" + self_comment = find_arguments([defitem.varname], before_contains_code) + const_or_var.comment = "" + const_or_var_type + " :: \n" + const_or_var.comment << self_comment if self_comment + progress const_or_var_progress + @stats.num_methods += 1 + container.add_method const_or_var + + set_visibility(container, defitem.varname, visibility_default, @@public_methods) + + if defitem.include_attr?("public") + container.set_visibility_for([defitem.varname], :public) + elsif defitem.include_attr?("private") + container.set_visibility_for([defitem.varname], :private) + end + + check_public_methods(const_or_var, container.name) + + + } if const_var_defs + + # Parse subroutines + # + contains_code = "" + while remaining_code =~ /^\s*? + (recursive|pure|elemental)?\s*? + subroutine\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ + (.*?) + ^(\s*?end\s+subroutine.*?)$ + /imx + remaining_code = $~.pre_match + remaining_code << $~.post_match + post_code = "#{$~.post_match}" + pre_code = "#{$~.pre_match}" + subname = $2.chomp.strip + params = $3 || "" + subroutine_code = remove_empty_head_lines($&) + subroutine_end = $6 + subroutine_prefix = $1 || "" + subroutine_trailing = $4 || "!" + next if subroutine_trailing =~ /!:nodoc:/ + + # + # If the subroutine contains internal sub procedures, + # they are parsed as private methods. + # + if subroutine_code =~ /^\s*?contains\s*?(!.*?)?$/ + before_contains = $~.pre_match + body_contains = $& + after_contains = $~.post_match + while after_contains =~ \ + /(.*?) + ^\s*?([\w\s\(\)]+\s+)? + subroutine\s+.*?(!.*?)?$ + (.*?) + ^(\s*end\s+subroutine.*?)$ + /imx + contains_code << $& + contains_code << "\n\n" + after_contains = $~.pre_match + after_contains << $~.post_match + end + while after_contains =~ \ + /(.*?) + ^\s*?([\w\s\(\)]+\s+)? + function\s+.*?(!.*?)?$ + (.*?) + ^(\s*end\s+function.*?)$ + /imx + contains_code << $& + contains_code << "\n\n" + after_contains = $~.pre_match + after_contains << $~.post_match + end + + if after_contains =~ /^(\s*end\s+subroutine.*?)$/i + subroutine_end = $& + subroutine_code = subroutine_code.sub(/^(\s*?end\s+subroutine.*?)$/, '') + + "\n" + contains_code + "\n" + subroutine_end + parse_program_or_module(container, contains_code, :private) + contains_code = "" + else + remaining_code = "#{pre_code}" + remaining_code << before_contains + remaining_code << body_contains + remaining_code << after_contains + remaining_code << "#{post_code}" + + next # To start of subroutine parse loop + + end + end # End of treatment of after "contains" + + # + # AnyMethod object for subroutine is created + # + subroutine_comment = COMMENTS_ARE_UPPER ? + "#{pre_code}" + "\n" + subroutine_trailing : + subroutine_trailing + "\n" + subroutine_code.sub(/^.*$\n/i, '') + subroutine = AnyMethod.new("subroutine", subname) + parse_subprogram(subroutine, params, + subroutine_comment, subroutine_code, + before_contains_code, nil, subroutine_prefix) + progress "s" + @stats.num_methods += 1 + container.add_method subroutine + + set_visibility(container, subname, visibility_default, @@public_methods) + check_external_aliases(subname, subroutine.params, subroutine.comment) if external + + check_public_methods(subroutine, container.name) + + end + + # Parse functions + # + contains_code = "" + while remaining_code =~ /^\s*? + (recursive|pure|elemental)?\s*? + ( + character\s*?(\([\w\s\=\(\)\*]+?\))?\s+ + | type\s*?\([\w\s]+?\)\s+ + | integer\s*?(\([\w\s\=\(\)\*]+?\))?\s+ + | real\s*?(\([\w\s\=\(\)\*]+?\))?\s+ + | double\s+precision\s+ + | logical\s*?(\([\w\s\=\(\)\*]+?\))?\s+ + | complex\s*?(\([\w\s\=\(\)\*]+?\))?\s+ + )? + function\s+(\w+)\s*? + (\(.*?\))?(\s+result\((.*?)\))?\s*?(!.*?)?$ + (.*?) + ^(\s*?end\s+function.*?)$ + /imx + + remaining_code = $~.pre_match + remaining_code << $~.post_match + post_code = "#{$~.post_match}" + pre_code = "#{$~.pre_match}" + function_prefix = $1 || "" + function_type = $2 ? $2.chomp.strip : nil + subname = $8.chomp.strip + params_org = $9 ? $9 : "" + function_code_org = remove_empty_head_lines($&) + function_result_arg = $11 ? $11.chomp.strip : subname + function_end = $14 + function_trailing = $12 || "!" + next if function_trailing =~ /!:nodoc:/ + + # + # If the function contains internal sub procedures, + # they are parsed as private methods. + # + if function_code_org =~ /^\s*?contains\s*?(!.*?)?$/ + before_contains = $~.pre_match + body_contains = $& + after_contains = $~.post_match + while after_contains =~ \ + /(.*?) + ^\s*?([\w\s\(\)]+\s+)? + subroutine\s+.*?(!.*?)?$ + (.*?) + ^(\s*end\s+subroutine.*?)$ + /imx + contains_code << $& + contains_code << "\n\n" + after_contains = $~.pre_match + after_contains << $~.post_match + end + while after_contains =~ \ + /(.*?) + ^\s*?([\w\s\(\)]+\s+)? + function\s+.*?(!.*?)?$ + (.*?) + ^(\s*end\s+function.*?)$ + /imx + contains_code << $& + contains_code << "\n\n" + after_contains = $~.pre_match + after_contains << $~.post_match + end + if after_contains =~ /^(\s*end\s+function.*?)$/i + function_end = $& + function_code_org = function_code_org.sub(/^(\s*?end\s+function.*?)$/, '') + + "\n" + contains_code + "\n" + function_end + parse_program_or_module(container, contains_code, :private) + contains_code = "" + else + remaining_code = "#{pre_code}" + remaining_code << before_contains + remaining_code << body_contains + remaining_code << after_contains + remaining_code << "#{post_code}" + + next # To start of function parse loop + + end + end # End of treatment of after "contains" + + # + # AnyMethod object for function is created + # + function_comment = COMMENTS_ARE_UPPER ? + "#{pre_code}" + "\n" + function_trailing : + function_trailing + "\n " + function_code_org.sub(/^.*$\n/i, '') + + function_code = "#{function_code_org}" + if function_type + function_code << "\n" + function_type + " :: " + function_result_arg + end + + params = params_org.sub(/^\(/, "\(#{function_result_arg}, ") + + function = AnyMethod.new("function", subname) + parse_subprogram(function, params, + function_comment, function_code, + before_contains_code, true, function_prefix) + + # Specific modification due to function + function.params.sub!(/\(\s*?#{function_result_arg}\s*?,\s*?/, "\( ") + function.params << " result(" + function_result_arg + ")" + function.start_collecting_tokens + function.add_token Token.new(1,1).set_text(function_code_org) + + progress "f" + @stats.num_methods += 1 + container.add_method function + + set_visibility(container, subname, visibility_default, @@public_methods) + + check_external_aliases(subname, function.params, function.comment) if external + + check_public_methods(function, container.name) + end + + # + # Parse interface + # + interface_scope = false + generic_name = "" + interface_code.split("\n").each{ |line| + if /^\s*? + interface( + \s+\w+| + \s+operator\s*?\(.*?\)| + \s+assignment\s*?\(\s*?=\s*?\) + )? + \s*?(!.*?)?$ + /ix =~ line + generic_name = $1 ? $1.strip.chomp : nil + interface_trailing = $2 || "!" + interface_scope = true + interface_scope = false if interface_trailing =~ /!:nodoc:/ +# if generic_name =~ /operator\s*?\((.*?)\)/i +# operator_name = $1 +# if operator_name && !operator_name.empty? +# generic_name = "#{operator_name}" +# end +# end +# if generic_name =~ /assignment\s*?\((.*?)\)/i +# assignment_name = $1 +# if assignment_name && !assignment_name.empty? +# generic_name = "#{assignment_name}" +# end +# end + end + if /^\s*?end\s+interface/i =~ line + interface_scope = false + generic_name = nil + end + # internal alias + if interface_scope && /^\s*?module\s+procedure\s+(.*?)(!.*?)?$/i =~ line + procedures = $1.strip.chomp + procedures_trailing = $2 || "!" + next if procedures_trailing =~ /!:nodoc:/ + procedures.split(",").each{ |proc| + proc.strip! + proc.chomp! + next if generic_name == proc || !generic_name + old_meth = container.find_symbol(proc, nil, @options.ignore_case) + next if !old_meth + nolink = old_meth.visibility == :private ? true : nil + nolink = nil if @options.show_all + new_meth = + initialize_external_method(generic_name, proc, + old_meth.params, nil, + old_meth.comment, + old_meth.clone.token_stream[0].text, + true, nolink) + new_meth.singleton = old_meth.singleton + + progress "i" + @stats.num_methods += 1 + container.add_method new_meth + + set_visibility(container, generic_name, visibility_default, @@public_methods) + + check_public_methods(new_meth, container.name) + + } + end + + # external aliases + if interface_scope && + /^\s*? + ([\w\s\(\)]+\s+)? + (subroutine|function)\s+(\w+)\s*?(\(.*?\))?\s*?(!.*?)?$ + /ix =~ line + proc = $3.chomp.strip + generic_name = proc unless generic_name + params = $4 ? $4 : "" + procedures_trailing = $5 || "!" + next if procedures_trailing =~ /!:nodoc:/ + indicated_method = nil + indicated_file = nil + TopLevel.all_files.each do |name, toplevel| + indicated_method = toplevel.find_local_symbol(proc, @options.ignore_case) + indicated_file = name + break if indicated_method + end + + if indicated_method + external_method = + initialize_external_method(generic_name, proc, + indicated_method.params, + indicated_file, + indicated_method.comment) + + progress "e" + @stats.num_methods += 1 + container.add_method external_method + set_visibility(container, generic_name, visibility_default, @@public_methods) + if !container.include_requires?(indicated_file, @options.ignore_case) + container.add_require(Require.new(indicated_file, "")) + end + check_public_methods(external_method, container.name) + + else + @@external_aliases << { + "new_name" => generic_name, + "old_name" => proc, + "file_or_module" => container, + "visibility" => find_visibility(container, generic_name, @@public_methods) || visibility_default + } + end + end + + } if interface_code # End of interface_code.split("\n").each ... + + # + # Already imported methods are removed from @@public_methods. + # Remainders are assumed to be imported from other modules. + # + # 既に参照済みのメソッドは @@public_methods から取り除く. + # 残りは外部モジュールからの参照と仮定する. + # + @@public_methods.delete_if{ |method| method["entity_is_discovered"]} + @@public_methods.each{ |pub_meth| + next unless pub_meth["file_or_module"].name == container.name + pub_meth["used_modules"].each{ |used_mod| + TopLevel.all_classes_and_modules.each{ |modules| + if modules.name == used_mod || + modules.name.upcase == used_mod.upcase && + @options.ignore_case + modules.method_list.each{ |meth| + if meth.name == pub_meth["name"] || + meth.name.upcase == pub_meth["name"].upcase && + @options.ignore_case + new_meth = initialize_public_method(meth, + modules.name) + if pub_meth["local_name"] + new_meth.name = pub_meth["local_name"] + end + progress "e" + @stats.num_methods += 1 + container.add_method new_meth + end + } + end + } + } + } + + container + end # End of parse_program_or_module + + # + # Parse arguments, comment, code of subroutine and function. + # Return AnyMethod object. + # + def parse_subprogram(subprogram, params, comment, code, + before_contains=nil, function=nil, prefix=nil) + subprogram.singleton = false + prefix = "" if !prefix + arguments = params.sub(/\(/, "").sub(/\)/, "").split(",") if params + args_comment, params_opt = + find_arguments(arguments, code.sub(/^s*?contains\s*?(!.*?)?$.*/im, ""), + nil, nil, true) + params_opt = "( " + params_opt + " ) " if params_opt + subprogram.params = params_opt || "" + namelist_comment = find_namelists(code, before_contains) + + block_comment = find_comments comment + if function + subprogram.comment = " Function :: #{prefix}\n" + else + subprogram.comment = " Subroutine :: #{prefix}\n" + end + subprogram.comment << args_comment if args_comment + subprogram.comment << block_comment if block_comment + subprogram.comment << namelist_comment if namelist_comment + + # For output source code + subprogram.start_collecting_tokens + subprogram.add_token Token.new(1,1).set_text(code) + + subprogram + end + + # + # Collect comment for file entity + # + def collect_first_comment(body) + comment = "" + not_comment = "" + comment_start = false + comment_end = false + body.split("\n").each{ |line| + if comment_end + not_comment << line + not_comment << "\n" + elsif /^\s*?!\s?(.*)$/i =~ line + comment_start = true + comment << $1 + comment << "\n" + elsif /^\s*?$/i =~ line + comment_end = true if comment_start && COMMENTS_ARE_UPPER + else + comment_end = true + not_comment << line + not_comment << "\n" + end + } + return comment, not_comment + end + + + # Return comments of definitions of arguments + # + # If "all" argument is true, information of all arguments are returned. + # If "modified_params" is true, list of arguments are decorated, + # for exameple, optional arguments are parenthetic as "[arg]". + # + def find_arguments(args, text, all=nil, indent=nil, modified_params=nil) + return unless args || all + indent = "" unless indent + args = ["all"] if all + params = "" if modified_params + comma = "" + return unless text + args_rdocforms = "\n" + remaining_lines = "#{text}" + definitions = definition_info(remaining_lines) + args.each{ |arg| + arg.strip! + arg.chomp! + definitions.each { |defitem| + if arg == defitem.varname.strip.chomp || all + args_rdocforms << <<-"EOF" + +#{indent}#{defitem.varname.chomp.strip}#{defitem.arraysuffix} #{defitem.inivalue} :: +#{indent} #{defitem.types.chomp.strip} +EOF + if !defitem.comment.chomp.strip.empty? + comment = "" + defitem.comment.split("\n").each{ |line| + comment << " " + line + "\n" + } + args_rdocforms << <<-"EOF" + +#{indent} :: +#{indent} +#{indent} #{comment.chomp.strip} +EOF + end + + if modified_params + if defitem.include_attr?("optional") + params << "#{comma}[#{arg}]" + else + params << "#{comma}#{arg}" + end + comma = ", " + end + end + } + } + if modified_params + return args_rdocforms, params + else + return args_rdocforms + end + end + + # Return comments of definitions of namelists + # + def find_namelists(text, before_contains=nil) + return nil if !text + result = "" + lines = "#{text}" + before_contains = "" if !before_contains + while lines =~ /^\s*?namelist\s+\/\s*?(\w+)\s*?\/([\s\w\,]+)$/i + lines = $~.post_match + nml_comment = COMMENTS_ARE_UPPER ? + find_comments($~.pre_match) : find_comments($~.post_match) + nml_name = $1 + nml_args = $2.split(",") + result << "\n\n=== NAMELIST " + nml_name + "\n\n" + result << nml_comment + "\n" if nml_comment + if lines.split("\n")[0] =~ /^\//i + lines = "namelist " + lines + end + result << find_arguments(nml_args, "#{text}" + "\n" + before_contains) + end + return result end + # + # Comments just after module or subprogram, or arguments are + # returnd. If "COMMENTS_ARE_UPPER" is true, comments just before + # modules or subprograms are returnd + # def find_comments text - lines = text.split("\n").reverse + return "" unless text + lines = text.split("\n") + lines.reverse! if COMMENTS_ARE_UPPER comment_block = Array.new lines.each do |line| - break if line =~ /^\s*\w/ - comment_block.unshift line.sub(/^!\s?/,"") + break if line =~ /^\s*?\w/ || line =~ /^\s*?$/ + if COMMENTS_ARE_UPPER + comment_block.unshift line.sub(/^\s*?!\s?/,"") + else + comment_block.push line.sub(/^\s*?!\s?/,"") + end end - nice_lines = comment_block.join("\n").split "\n\s*\n" - nice_lines.shift - nice_lines.shift + nice_lines = comment_block.join("\n").split "\n\s*?\n" + nice_lines[0] ||= "" nice_lines.shift end @@ -114,6 +1352,543 @@ end end + # + # Create method for internal alias + # + def initialize_public_method(method, parent) + return if !method || !parent + + new_meth = AnyMethod.new("External Alias for module", method.name) + new_meth.singleton = method.singleton + new_meth.params = method.params.clone + new_meth.comment = remove_trailing_alias(method.comment.clone) + new_meth.comment << "\n\n#{EXTERNAL_ALIAS_MES} #{parent.strip.chomp}\##{method.name}" + + return new_meth + end + + # + # Create method for external alias + # + # If argument "internal" is true, file is ignored. + # + def initialize_external_method(new, old, params, file, comment, token=nil, + internal=nil, nolink=nil) + return nil unless new || old + + if internal + external_alias_header = "#{INTERNAL_ALIAS_MES} " + external_alias_text = external_alias_header + old + elsif file + external_alias_header = "#{EXTERNAL_ALIAS_MES} " + external_alias_text = external_alias_header + file + "#" + old + else + return nil + end + external_meth = AnyMethod.new(external_alias_text, new) + external_meth.singleton = false + external_meth.params = params + external_comment = remove_trailing_alias(comment) + "\n\n" if comment + external_meth.comment = external_comment || "" + if nolink && token + external_meth.start_collecting_tokens + external_meth.add_token Token.new(1,1).set_text(token) + else + external_meth.comment << external_alias_text + end + + return external_meth + end + + + + # + # Parse visibility + # + def parse_visibility(code, default, container) + result = [] + visibility_default = default || :public + + used_modules = [] + container.includes.each{|i| used_modules << i.name} if container + + remaining_code = code.gsub(/^\s*?type[\s\,]+.*?\s+end\s+type.*?$/im, "") + remaining_code.split("\n").each{ |line| + if /^\s*?private\s*?$/ =~ line + visibility_default = :private + break + end + } if remaining_code + + remaining_code.split("\n").each{ |line| + if /^\s*?private\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line + methods = $2.sub(/!.*$/, '') + methods.split(",").each{ |meth| + meth.sub!(/!.*$/, '') + meth.gsub!(/:/, '') + result << { + "name" => meth.chomp.strip, + "visibility" => :private, + "used_modules" => used_modules.clone, + "file_or_module" => container, + "entity_is_discovered" => nil, + "local_name" => nil + } + } + elsif /^\s*?public\s*?(::)?\s+(.*)\s*?(!.*?)?/i =~ line + methods = $2.sub(/!.*$/, '') + methods.split(",").each{ |meth| + meth.sub!(/!.*$/, '') + meth.gsub!(/:/, '') + result << { + "name" => meth.chomp.strip, + "visibility" => :public, + "used_modules" => used_modules.clone, + "file_or_module" => container, + "entity_is_discovered" => nil, + "local_name" => nil + } + } + end + } if remaining_code + + if container + result.each{ |vis_info| + vis_info["parent"] = container.name + } + end + + return visibility_default, result + end + + # + # Set visibility + # + # "subname" element of "visibility_info" is deleted. + # + def set_visibility(container, subname, visibility_default, visibility_info) + return unless container || subname || visibility_default || visibility_info + not_found = true + visibility_info.collect!{ |info| + if info["name"] == subname || + @options.ignore_case && info["name"].upcase == subname.upcase + if info["file_or_module"].name == container.name + container.set_visibility_for([subname], info["visibility"]) + info["entity_is_discovered"] = true + not_found = false + end + end + info + } + if not_found + return container.set_visibility_for([subname], visibility_default) + else + return container + end + end + + # + # Find visibility + # + def find_visibility(container, subname, visibility_info) + return nil if !subname || !visibility_info + visibility_info.each{ |info| + if info["name"] == subname || + @options.ignore_case && info["name"].upcase == subname.upcase + if info["parent"] == container.name + return info["visibility"] + end + end + } + return nil + end + + # + # Check external aliases + # + # subname というサブルーチン名, または関数名を持つファイルを + # 探査し, 存在する場合にはそのファイル内へメソッドを追加する. + # + def check_external_aliases(subname, params, comment) + @@external_aliases.each{ |alias_item| + if subname == alias_item["old_name"] || + subname.upcase == alias_item["old_name"].upcase && + @options.ignore_case + progress "e" + @stats.num_methods += 1 + alias_item["file_or_module"].add_method( \ + initialize_external_method(alias_item["new_name"], + subname, params, @file_name, + comment) ) + alias_item["file_or_module"].set_visibility_for([alias_item["new_name"]], alias_item["visibility"]) + + if !alias_item["file_or_module"].include_requires?(@file_name, @options.ignore_case) + alias_item["file_or_module"].add_require(Require.new(@file_name, "")) + end + + end + } + end + + # + # Check public_methods + # + # use したモジュールからそのまま引き継いで public として + # 公開する場合のチェックを行う. + # subname というサブルーチン名, または関数名を持つファイルを + # 探査し, 存在する場合にはそのファイル内へメソッドを追加する. + # + def check_public_methods(method, parent) + return if !method || !parent + @@public_methods.each{ |alias_item| + parent_is_used_module = nil + alias_item["used_modules"].each{ |used_module| + if used_module == parent || + used_module.upcase == parent.upcase && + @options.ignore_case + parent_is_used_module = true + end + } + next if !parent_is_used_module + + if method.name == alias_item["name"] || + method.name.upcase == alias_item["name"].upcase && + @options.ignore_case + + new_meth = initialize_public_method(method, parent) + if alias_item["local_name"] + new_meth.name = alias_item["local_name"] + end + + progress "e" + @stats.num_methods += 1 + alias_item["file_or_module"].add_method new_meth