yard-0.8.7.3/0000755000004100000410000000000012261240652012656 5ustar www-datawww-datayard-0.8.7.3/Rakefile0000644000004100000410000000275212261240652014331 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/lib/yard' require File.dirname(__FILE__) + '/lib/yard/rubygems/specification' require 'rbconfig' YARD::VERSION.replace(ENV['YARD_VERSION']) if ENV['YARD_VERSION'] task :default => :specs desc "Builds the gem" task :gem do Gem::Builder.new(eval(File.read('yard.gemspec'))).build end desc "Installs the gem" task :install => :gem do sh "gem install yard-#{YARD::VERSION}.gem --no-rdoc --no-ri" end begin require 'rvm-tester' RVM::Tester::TesterTask.new do |t| t.rubies = %w(1.8.6 ree jruby 1.8.7 1.9.2 1.9.3) t.bundle_install = false # don't need to do this all the time t.verbose = true end rescue LoadError end task :travis_ci do ENV['SUITE'] = '1' ENV['CI'] = '1' ENV['LEGACY'] = nil Rake::Task['specs'].execute if RUBY_VERSION >= '1.9' && RUBY_PLATFORM != 'java' puts "" puts "Running specs with in legacy mode" ENV['LEGACY'] = '1' Rake::Task['specs'].execute end end desc "Run all specs" task :specs do opts = ['rspec', '-c'] opts += ["--require", File.join(File.dirname(__FILE__), 'spec', 'spec_helper')] opts += ['-I', YARD::ROOT] if ENV['DEBUG'] $DEBUG = true opts += ['-d'] end opts += FileList["spec/**/*_spec.rb"].sort cmd = opts.join(' ') puts cmd if Rake.application.options.trace system(cmd) raise "Command failed with status (#{$?.to_i}): #{cmd}" if $?.to_i != 0 end task :spec => :specs YARD::Rake::YardocTask.new do |t| t.options += ['--title', "YARD #{YARD::VERSION} Documentation"] end yard-0.8.7.3/bin/0000755000004100000410000000000012261240652013426 5ustar www-datawww-datayard-0.8.7.3/bin/yard0000755000004100000410000000047412261240652014320 0ustar www-datawww-data#!/usr/bin/env ruby # We do all this work just to find the proper load path path = __FILE__ while File.symlink?(path) path = File.expand_path(File.readlink(path), File.dirname(path)) end $:.unshift(File.join(File.dirname(File.expand_path(path)), '..', 'lib')) require 'yard' YARD::CLI::CommandParser.run(*ARGV) yard-0.8.7.3/bin/yri0000755000004100000410000000046212261240652014161 0ustar www-datawww-data#!/usr/bin/env ruby # We do all this work just to find the proper load path path = __FILE__ while File.symlink?(path) path = File.expand_path(File.readlink(path), File.dirname(path)) end $:.unshift(File.join(File.dirname(File.expand_path(path)), '..', 'lib')) require 'yard' YARD::CLI::YRI.run(*ARGV) yard-0.8.7.3/bin/yardoc0000755000004100000410000000046512261240652014642 0ustar www-datawww-data#!/usr/bin/env ruby # We do all this work just to find the proper load path path = __FILE__ while File.symlink?(path) path = File.expand_path(File.readlink(path), File.dirname(path)) end $:.unshift(File.join(File.dirname(File.expand_path(path)), '..', 'lib')) require 'yard' YARD::CLI::Yardoc.run(*ARGV) yard-0.8.7.3/templates/0000755000004100000410000000000012261240652014654 5ustar www-datawww-datayard-0.8.7.3/templates/default/0000755000004100000410000000000012261240652016300 5ustar www-datawww-datayard-0.8.7.3/templates/default/tags/0000755000004100000410000000000012261240652017236 5ustar www-datawww-datayard-0.8.7.3/templates/default/tags/html/0000755000004100000410000000000012261240652020202 5ustar www-datawww-datayard-0.8.7.3/templates/default/tags/html/index.erb0000644000004100000410000000005312261240652022001 0ustar www-datawww-data
<%= yieldall %>
yard-0.8.7.3/templates/default/tags/html/see.erb0000644000004100000410000000031712261240652021451 0ustar www-datawww-data<% if object.has_tag?(:see) %>

See Also:

<% end %>yard-0.8.7.3/templates/default/tags/html/example.erb0000644000004100000410000000060112261240652022324 0ustar www-datawww-data<% if object.has_tag?(:example) %>

Examples:

<% object.tags(:example).each do |tag| %> <% unless tag.name.empty? %>

<%= htmlify_line(tag.name) %>

<% end %>
<%= html_syntax_highlight(tag.text) %>
<% end %>
<% end %>yard-0.8.7.3/templates/default/tags/html/overload.erb0000644000004100000410000000104612261240652022510 0ustar www-datawww-data<% if object.tags(:overload).size == 1 %> <%= yieldall :object => object.tag(:overload) %> <% elsif object.has_tag?(:overload) && object.tags(:overload).any? {|o| !o.docstring.blank? } %>

Overloads:

<% end %>yard-0.8.7.3/templates/default/tags/html/tag.erb0000644000004100000410000000137612261240652021456 0ustar www-datawww-data

<%= @label ? @label : YARD::Tags::Library.labels[@name] %>:

yard-0.8.7.3/templates/default/tags/html/option.erb0000644000004100000410000000156512261240652022213 0ustar www-datawww-data<% if object.has_tag?(:option) %> <% object.parameters.each do |param, default| %> <% tags = object.tags(:option).select {|x| x.name.to_s == param.to_s } %> <% next if tags.empty? %>

Options Hash (<%= param %>):

<% end %> <% end %> yard-0.8.7.3/templates/default/tags/text/0000755000004100000410000000000012261240652020222 5ustar www-datawww-datayard-0.8.7.3/templates/default/tags/text/index.erb0000644000004100000410000000002012261240652022013 0ustar www-datawww-data<%= yieldall %> yard-0.8.7.3/templates/default/tags/text/see.erb0000644000004100000410000000034212261240652021467 0ustar www-datawww-data<% if object.has_tag?(:see) %> See Also: --------- <% for tag in object.tags(:see) %> <% text = "- " + tag.name %> <% text += " - " + tag.text if tag.text && !tag.text.empty? %> <%= indent(wrap(text)) %> <% end %> <% end %> yard-0.8.7.3/templates/default/tags/text/example.erb0000644000004100000410000000043012261240652022344 0ustar www-datawww-data<% if object.has_tag?(:example) %> Examples: --------- <% object.tags(:example).each_with_index do |tag, i| %> <%= indent("# " + tag.name + "\n") if tag.name %> <%= indent(format_source(tag.text)) + "\n" %> <%= "\n" if i < object.tags(:example).size - 1 %> <% end %> <% end %> yard-0.8.7.3/templates/default/tags/text/overload.erb0000644000004100000410000000057312261240652022534 0ustar www-datawww-data<% if object.tags(:overload).size == 1 %> <%= wrap(yieldall(:object => object.tag(:overload))) %> <% elsif object.has_tag?(:overload) %> Overloads: ---------- <% object.tags(:overload).each do |overload| %> <% if overload.tags.size > 0 %> <%= hr %> <%= indent signature(overload) %> <%= hr %> <%= indent(wrap(yieldall(:object => overload))) %> <% end %> <% end %> <% end %> yard-0.8.7.3/templates/default/tags/text/tag.erb0000644000004100000410000000065612261240652021476 0ustar www-datawww-data<% title = @label ? @label : YARD::Tags::Library.labels[@name] %> <%= title %>: <%= hr(title.length) %>- <% object.tags(@name).each do |tag| %> <% text = "" %> <% text += format_types(tag.types) + " " unless @no_types || tag.types.nil? %> <% text += tag.name.to_s + " " unless @no_names %> <% text += "- " unless @no_names && @no_types %> <% text += tag.text if tag.text && !tag.text.empty? %> <%= indent wrap(text) %> <% end %>yard-0.8.7.3/templates/default/tags/text/option.erb0000644000004100000410000000112712261240652022225 0ustar www-datawww-data<% if object.has_tag?(:option) %> <% object.parameters.each do |param, default| %> <% tags = object.tags(:option).select {|x| x.name.to_s == param.to_s } %> <% next if tags.empty? %> Options Hash (<%= param %>): --------------<%= hr(param.to_s.length) %>-- <% for tag in tags %> <% text = "" %> <% text += format_types(tag.pair.types || ['Object']) %> <% text += " " + tag.pair.name.to_s %> <% if tag.pair.defaults %> <% text += " - default: " + tag.pair.defaults.join(", ") %> <% end %> <% text += " - " + tag.pair.text if tag.pair.text %> <%= indent(wrap(text)) %> <% end %> <% end %> <% end %> yard-0.8.7.3/templates/default/tags/setup.rb0000644000004100000410000000245012261240652020724 0ustar www-datawww-datadef init tags = Tags::Library.visible_tags - [:abstract, :deprecated, :note, :todo] create_tag_methods(tags - [:example, :option, :overload, :see]) sections :index, tags.map {|t| t.to_s.gsub('.', '_').to_sym } sections.any(:overload).push(T('docstring')) end def return if object.type == :method return if object.constructor? return if object.tags(:return).size == 1 && object.tag(:return).types == ['void'] end tag(:return) end def param tag(:param) if object.type == :method end private def tag(name, opts = nil) return unless object.has_tag?(name) opts ||= options_for_tag(name) @no_names = true if opts[:no_names] @no_types = true if opts[:no_types] @name = name out = erb('tag') @no_names, @no_types = nil, nil out end def create_tag_methods(tags) tags.each do |tag| tag_meth = tag.to_s.gsub('.', '_') next if respond_to?(tag_meth) instance_eval(<<-eof, __FILE__, __LINE__ + 1) def #{tag_meth}; tag(#{tag.inspect}) end eof end end def options_for_tag(tag) opts = {:no_types => true, :no_names => true} case Tags::Library.factory_method_for(tag) when :with_types opts[:no_types] = false when :with_types_and_name opts[:no_types] = false opts[:no_names] = false when :with_name opts[:no_names] = false end opts end yard-0.8.7.3/templates/default/docstring/0000755000004100000410000000000012261240652020274 5ustar www-datawww-datayard-0.8.7.3/templates/default/docstring/html/0000755000004100000410000000000012261240652021240 5ustar www-datawww-datayard-0.8.7.3/templates/default/docstring/html/index.erb0000644000004100000410000000012712261240652023041 0ustar www-datawww-data
<%= yieldall %>
yard-0.8.7.3/templates/default/docstring/html/returns_void.erb0000644000004100000410000000011012261240652024445 0ustar www-datawww-data

This method returns an undefined value.

yard-0.8.7.3/templates/default/docstring/html/todo.erb0000644000004100000410000000022012261240652022671 0ustar www-datawww-data<% object.tags(:todo).each do |tag| %>
TODO: <%= htmlify_line tag.text %>
<% end %> yard-0.8.7.3/templates/default/docstring/html/note.erb0000644000004100000410000000022312261240652022674 0ustar www-datawww-data<% object.tags(:note).each do |tag| %>
Note: <%= htmlify_line tag.text %>
<% end %> yard-0.8.7.3/templates/default/docstring/html/abstract.erb0000644000004100000410000000021412261240652023532 0ustar www-datawww-data
This <%= object.type %> is abstract. <%= htmlify_line object.tag(:abstract).text %>
yard-0.8.7.3/templates/default/docstring/html/deprecated.erb0000644000004100000410000000016112261240652024030 0ustar www-datawww-data
Deprecated. <%= htmlify_line object.tag(:deprecated).text %>
yard-0.8.7.3/templates/default/docstring/html/private.erb0000644000004100000410000000032312261240652023402 0ustar www-datawww-data

This <%= object.type %> is part of a private API. You should avoid using this <%= object.type %> if possible, as it may be removed or be changed in the future.

yard-0.8.7.3/templates/default/docstring/html/text.erb0000644000004100000410000000003712261240652022716 0ustar www-datawww-data<%= htmlify(docstring_text) %> yard-0.8.7.3/templates/default/docstring/text/0000755000004100000410000000000012261240652021260 5ustar www-datawww-datayard-0.8.7.3/templates/default/docstring/text/index.erb0000644000004100000410000000002112261240652023052 0ustar www-datawww-data <%= yieldall %> yard-0.8.7.3/templates/default/docstring/text/returns_void.erb0000644000004100000410000000007612261240652024500 0ustar www-datawww-data<%= indent(wrap("This method returns an undefined value.")) %>yard-0.8.7.3/templates/default/docstring/text/todo.erb0000644000004100000410000000013212261240652022713 0ustar www-datawww-data<% object.tags(:todo).each do |tag| %> <%= indent(wrap("TODO: #{tag.text}")) %> <% end %>yard-0.8.7.3/templates/default/docstring/text/note.erb0000644000004100000410000000013212261240652022713 0ustar www-datawww-data<% object.tags(:note).each do |tag| %> <%= indent(wrap("Note: #{tag.text}")) %> <% end %>yard-0.8.7.3/templates/default/docstring/text/abstract.erb0000644000004100000410000000010012261240652023544 0ustar www-datawww-data<%= indent(wrap("Abstract. #{object.tag(:abstract).text}")) %> yard-0.8.7.3/templates/default/docstring/text/deprecated.erb0000644000004100000410000000010412261240652024045 0ustar www-datawww-data<%= indent(wrap("Deprecated. #{object.tag(:deprecated).text}")) %> yard-0.8.7.3/templates/default/docstring/text/private.erb0000644000004100000410000000010612261240652023421 0ustar www-datawww-data<%= indent(wrap("This #{object.type} is part of a private API.")) %> yard-0.8.7.3/templates/default/docstring/text/text.erb0000644000004100000410000000006012261240652022732 0ustar www-datawww-data<%= indent wrap(h(docstring_text.strip), 68) %> yard-0.8.7.3/templates/default/docstring/setup.rb0000644000004100000410000000235012261240652021761 0ustar www-datawww-datadef init return if object.docstring.blank? && !object.has_tag?(:api) sections :index, [:private, :deprecated, :abstract, :todo, :note, :returns_void, :text], T('tags') end def private return unless object.has_tag?(:api) && object.tag(:api).text == 'private' erb(:private) end def abstract return unless object.has_tag?(:abstract) erb(:abstract) end def deprecated return unless object.has_tag?(:deprecated) erb(:deprecated) end def todo return unless object.has_tag?(:todo) erb(:todo) end def note return unless object.has_tag?(:note) erb(:note) end def returns_void return unless object.type == :method return if object.name == :initialize && object.scope == :instance return unless object.tags(:return).size == 1 && object.tag(:return).types == ['void'] erb(:returns_void) end def docstring_text text = "" unless object.tags(:overload).size == 1 && object.docstring.empty? text = object.docstring end if text.strip.empty? && object.tags(:return).size == 1 && object.tag(:return).text text = object.tag(:return).text.gsub(/\A([a-z])/) {|x| x.downcase } text = "Returns #{text}" unless text.empty? || text =~ /^\s*return/i text = text.gsub(/\A([a-z])/) {|x| x.upcase } end text.strip endyard-0.8.7.3/templates/default/root/0000755000004100000410000000000012261240652017263 5ustar www-datawww-datayard-0.8.7.3/templates/default/root/html/0000755000004100000410000000000012261240652020227 5ustar www-datawww-datayard-0.8.7.3/templates/default/root/html/setup.rb0000644000004100000410000000004012261240652021706 0ustar www-datawww-datainclude T('default/module/html')yard-0.8.7.3/templates/default/root/dot/0000755000004100000410000000000012261240652020051 5ustar www-datawww-datayard-0.8.7.3/templates/default/root/dot/child.erb0000644000004100000410000000013312261240652021623 0ustar www-datawww-data<% if inner = yieldall.gsub("\n", '') %> Root [label="{<%= inner %>}" rank=sink]; <% end %>yard-0.8.7.3/templates/default/root/dot/setup.rb0000644000004100000410000000010112261240652021526 0ustar www-datawww-datainclude T('default/module/dot') def format_path(object) "" endyard-0.8.7.3/templates/default/method_details/0000755000004100000410000000000012261240652021265 5ustar www-datawww-datayard-0.8.7.3/templates/default/method_details/html/0000755000004100000410000000000012261240652022231 5ustar www-datawww-datayard-0.8.7.3/templates/default/method_details/html/source.erb0000644000004100000410000000055512261240652024230 0ustar www-datawww-data
<%= "\n\n\n" %><%= h format_lines(object) %>
# File '<%= h object.file %>'<% if object.line %>, line <%= object.line %><% end %><%= "\n\n" %><%= html_syntax_highlight object.source %>
yard-0.8.7.3/templates/default/method_details/html/method_signature.erb0000644000004100000410000000157512261240652026274 0ustar www-datawww-data

<% if object.tags(:overload).size == 1 %> <%= signature(object.tag(:overload), false) %> <% elsif object.tags(:overload).size > 1 %> <% object.tags(:overload).each do |overload| %> <%= signature(overload, false) %> <% end %> <% else %> <%= signature(object, false) %> <% end %> <% if object.aliases.size > 0 %> Also known as: <%= object.aliases.map {|o| "" + h(o.name.to_s) + "" }.join(", ") %> <% end %> <% if owner != object.namespace %> Originally defined in <%= object.namespace.type %> <%= linkify object, owner.relative_path(object.namespace) %> <% end %>

yard-0.8.7.3/templates/default/method_details/html/header.erb0000644000004100000410000000012712261240652024153 0ustar www-datawww-data
<%= yieldall %>
yard-0.8.7.3/templates/default/method_details/text/0000755000004100000410000000000012261240652022251 5ustar www-datawww-datayard-0.8.7.3/templates/default/method_details/text/method_signature.erb0000644000004100000410000000046412261240652026310 0ustar www-datawww-data <% if object.tags(:overload).size == 1 %> <%= indent wrap(signature(object.tag(:overload))) %> <% elsif object.tags(:overload).size > 1 %> <% object.tags(:overload).each do |overload| %> <%= indent wrap(signature(overload)) %> <% end %> <% else %> <%= indent wrap(signature(object)) %> <% end %> <%= hr %> yard-0.8.7.3/templates/default/method_details/text/setup.rb0000644000004100000410000000027512261240652023742 0ustar www-datawww-datadef init super sections.last.pop end def format_object_title(object) title = "Method: #{object.name(true)}" title += " (#{object.namespace})" if !object.namespace.root? title endyard-0.8.7.3/templates/default/method_details/text/header.erb0000644000004100000410000000040512261240652024172 0ustar www-datawww-data<%= title_align_right format_object_title(object) %> <%= align_right "(Defined in: #{object.file})" %> <% if object.aliases.size > 0 %> <%= align_right "(Also known as: #{object.aliases.map {|o| o.name(true).to_s }.join(',')})" %> <% end %> <%= yieldall %> yard-0.8.7.3/templates/default/method_details/setup.rb0000644000004100000410000000033312261240652022751 0ustar www-datawww-datadef init sections :header, [:method_signature, T('docstring'), :source] end def source return if owner != object.namespace return if Tags::OverloadTag === object return if object.source.nil? erb(:source) end yard-0.8.7.3/templates/default/module/0000755000004100000410000000000012261240652017565 5ustar www-datawww-datayard-0.8.7.3/templates/default/module/html/0000755000004100000410000000000012261240652020531 5ustar www-datawww-datayard-0.8.7.3/templates/default/module/html/inherited_methods.erb0000644000004100000410000000200512261240652024716 0ustar www-datawww-data<% found_method = false %> <% object.inheritance_tree(true)[1..-1].each do |superclass| %> <% next if superclass.is_a?(YARD::CodeObjects::Proxy) %> <% next if options.embed_mixins.size > 0 && options.embed_mixins_match?(superclass) != false %> <% meths = prune_method_listing(superclass.meths(:included => false, :inherited => false)) %> <% meths.reject! {|m| object.child(:scope => m.scope, :name => m.name) != nil } %> <% meths.reject! {|m| m.is_alias? || m.is_attribute? } %> <% next if meths.size == 0 %> <% if method_listing.size == 0 && !found_method %>

Method Summary

<% end %> <% found_method = true %>

Methods <%= superclass.type == :class ? 'inherited' : 'included' %> from <%= linkify superclass %>

<%= meths.sort_by {|o| o.name.to_s }.map do |m| name = m.name(true) name = name.gsub(/^#/,'') if superclass.type == :module && object.class_mixins.include?(superclass) linkify(m, name) end.join(", ") %>

<% end %>yard-0.8.7.3/templates/default/module/html/pre_docstring.erb0000644000004100000410000000002112261240652024056 0ustar www-datawww-data

Overview

yard-0.8.7.3/templates/default/module/html/inherited_constants.erb0000644000004100000410000000063512261240652025276 0ustar www-datawww-data<% found_const = false %> <% inherited_constant_list do |superclass, consts| %> <% if constant_listing.size == 0 && !found_const %>

Constant Summary

<% end %> <% found_const = true %>

Constants <%= superclass.type == :class ? 'inherited' : 'included' %> from <%= linkify superclass %>

<%= consts.map {|c| linkify c }.join(", ") %>

<% end %> yard-0.8.7.3/templates/default/module/html/methodmissing.erb0000644000004100000410000000072412261240652024100 0ustar www-datawww-data

Dynamic Method Handling

This class handles dynamic methods through the method_missing method <% if @mm.namespace != object %> in the class <%= linkify @mm, @mm.namespace.path %> <% end %>

<% if @mm.namespace == object %> <%= yieldall :object => @mm, :index => 0 %> <% end %>
yard-0.8.7.3/templates/default/module/html/method_details_list.erb0000644000004100000410000000050612261240652025244 0ustar www-datawww-data<% scopes(method_listing(false)) do |list, scope| %>

<%= scope.to_s.capitalize %> Method Details

<% list.each_with_index do |meth, i| %> <%= yieldall :object => meth, :owner => object, :index => i %> <% end %>
<% end %> yard-0.8.7.3/templates/default/module/html/item_summary.erb0000644000004100000410000000364712261240652023750 0ustar www-datawww-data
  • <% if @item.tags(:overload).size == 1 %> <%= signature(@item.tag(:overload), true, !@item.attr_info) %> <% else %> <%= signature(@item, true, false, !@item.attr_info) %> <% end %> <% if @item.aliases.size > 0 %> (also: <%= @item.aliases.map {|o| h(o.name(true)) }.join(", ") %>) <% end %> <% if object != @item.namespace %> <%= @item.namespace.type == :class ? 'inherited' : (@item.scope == :class ? 'extended' : 'included') %> from <%= linkify @item, object.relative_path(@item.namespace) %> <% end %> <% if @item.constructor? %> constructor <% end %> <% if rw = @item.attr_info %> <% if !run_verifier([rw[:read]].compact).empty? && run_verifier([rw[:write]].compact).empty? %> readonly <% end %> <% if !run_verifier([rw[:write]].compact).empty? && run_verifier([rw[:read]].compact).empty? %> writeonly <% end %> <% end %> <% if @item.visibility != :public %><%= @item.visibility %><% end %> <% if @item.has_tag?(:abstract) %>abstract<% end %> <% if @item.has_tag?(:deprecated) %>deprecated<% end %> <% if @item.has_tag?(:api) && @item.tag(:api).text == 'private' %>private<% end %> <% if @item.has_tag?(:deprecated) %> Deprecated. <%= htmlify_line @item.tag(:deprecated).text %> <% else %> <%= htmlify_line docstring_summary(@item) %> <% end %>
  • yard-0.8.7.3/templates/default/module/html/children.erb0000644000004100000410000000044312261240652023014 0ustar www-datawww-data

    Defined Under Namespace

    <% @inner.each do |name, list| %> <% if list.size > 0 %> <%= name.to_s.capitalize %>: <%= list.map {|child| linkify(child, child.name(true)) }.join(", ") %> <% end %> <% end %>

    yard-0.8.7.3/templates/default/module/html/method_summary.erb0000644000004100000410000000051312261240652024257 0ustar www-datawww-data<% if method_listing.size > 0 %> <% groups(method_listing) do |list, name| %>

    <%= name %> (collapse)

    <% end %> <% end %>yard-0.8.7.3/templates/default/module/html/inherited_attributes.erb0000644000004100000410000000117212261240652025445 0ustar www-datawww-data<% found_method = false %> <% inherited_attr_list do |superclass, attribs| %> <% if attr_listing.size == 0 && !found_method %>

    Instance Attribute Summary

    <% end %> <% found_method = true %>

    Attributes <%= superclass.type == :class ? 'inherited' : 'included' %> from <%= linkify superclass %>

    <%= attribs.map do |method| name = method.name(true).gsub(/=$/, '') if superclass.type == :module && object.instance_mixins.include?(superclass) name = "##{name}" unless name =~ /^#/ end linkify(method, name) end.join(", ") %>

    <% end %> yard-0.8.7.3/templates/default/module/html/attribute_details.erb0000644000004100000410000000064412261240652024737 0ustar www-datawww-data<% scopes(attr_listing) do |list, scope| %>

    <%= scope.to_s.capitalize %> Attribute Details

    <% list.each_with_index do |meth, i| %> <% rw = meth.attr_info %> <%= yieldall :object => meth, :owner => object, :index => i %> <% end %>
    <% end %> yard-0.8.7.3/templates/default/module/html/box_info.erb0000644000004100000410000000261712261240652023034 0ustar www-datawww-data<% n = 1 %>
    <% if CodeObjects::ClassObject === object && object.superclass %>
    Inherits:
    <%= linkify object.superclass %> <% if object.superclass.name != :BasicObject %> show all <% end %>
    <% n = 2 %> <% end %> <% [[:class, "Extended by"], [:instance, "Includes"]].each do |scope, name| %> <% if (mix = run_verifier(object.mixins(scope))).size > 0 %>
    <%= name %>:
    <%= mix.sort_by {|o| o.path }.map {|o| linkify(o) }.join(", ") %>
    <% n = n == 2 ? 1 : 2 %> <% end %> <% end %> <% if (mixed_into = mixed_into(object)).size > 0 %>
    Included in:
    <%= mixed_into.sort_by {|o| o.path }.map {|o| linkify(o) }.join(", ") %>
    <% n = n == 2 ? 1 : 2 %> <% end %> <% unless object.root? %>
    Defined in:
    <%= erb(:defines) %>
    <% end %>
    yard-0.8.7.3/templates/default/module/html/header.erb0000644000004100000410000000056212261240652022456 0ustar www-datawww-data

    <%= format_object_title(object) %> <% if object.has_tag?(:abstract) %>Abstract<% end %> <% if object.has_tag?(:deprecated) %>Deprecated<% end %> <% if object.has_tag?(:api) && object.tag(:api).text == 'private' %>Private<% end %>

    yard-0.8.7.3/templates/default/module/html/attribute_summary.erb0000644000004100000410000000041112261240652024777 0ustar www-datawww-data<% groups(attr_listing, "Attribute") do |list, name| %>

    <%= name %> (collapse)

    <% end %> yard-0.8.7.3/templates/default/module/html/defines.erb0000644000004100000410000000027312261240652022642 0ustar www-datawww-data<%= object.file ? object.file : '(unknown)' %><% if object.files.size > 1 %>,
    <%= object.files[1..-1].map {|f| f.first }.join(",
    ") %>
    <% end %>yard-0.8.7.3/templates/default/module/html/constant_summary.erb0000644000004100000410000000076512261240652024641 0ustar www-datawww-data<% if constant_listing.size > 0 || object.constants.size > 0 %>

    Constant Summary

    <% if constant_listing.size > 0 %>
    <% constant_listing.each do |cnst| %>
    <%= cnst.name %> = <%= yieldall :object => cnst %>
    <%= format_constant cnst.value %>
    <% end %>
    <% end %> <% end %> yard-0.8.7.3/templates/default/module/text/0000755000004100000410000000000012261240652020551 5ustar www-datawww-datayard-0.8.7.3/templates/default/module/text/instance_meths_list.erb0000644000004100000410000000023212261240652025277 0ustar www-datawww-data<% if instance_meths.size > 0 %> Instance methods: ----------------- <%= indent wrap(instance_meths.map {|o| o.name.to_s }.join(", "), 68) %> <% end %>yard-0.8.7.3/templates/default/module/text/extends.erb0000644000004100000410000000020712261240652022714 0ustar www-datawww-data<% if object.mixins(:class).size > 0 %> Extended by: ------------ <%= indent wrap(object.mixins(:class).join(", "), 68) %> <% end %>yard-0.8.7.3/templates/default/module/text/class_meths_list.erb0000644000004100000410000000021612261240652024602 0ustar www-datawww-data<% if class_meths.size > 0 %> Class methods: -------------- <%= indent wrap(class_meths.map {|o| o.name.to_s }.join(", "), 68) %> <% end %>yard-0.8.7.3/templates/default/module/text/children.erb0000644000004100000410000000033012261240652023027 0ustar www-datawww-dataDefined Under Namespace: ------------------------ <% @inner.each do |name, list| %> <% if list.size > 0 %> <% text = list.map {|c| c.name }.join(", ") + " (#{name})" %> <%= indent(wrap(text)) %> <% end %> <% end %>yard-0.8.7.3/templates/default/module/text/includes.erb0000644000004100000410000000020712261240652023050 0ustar www-datawww-data<% if object.mixins(:instance).size > 0 %> Includes: --------- <%= indent wrap(object.mixins(:instance).join(", "), 68) %> <% end %>yard-0.8.7.3/templates/default/module/text/setup.rb0000644000004100000410000000045712261240652022244 0ustar www-datawww-datadef init sections :header, [T('docstring')], :children, :includes, :extends, :class_meths_list, :instance_meths_list end def class_meths @classmeths ||= method_listing.select {|o| o.scope == :class } end def instance_meths @instmeths ||= method_listing.select {|o| o.scope == :instance } endyard-0.8.7.3/templates/default/module/text/header.erb0000644000004100000410000000012312261240652022467 0ustar www-datawww-data<%= title_align_right format_object_title(object) %> <%= yieldall %> <%= hr %> yard-0.8.7.3/templates/default/module/dot/0000755000004100000410000000000012261240652020353 5ustar www-datawww-datayard-0.8.7.3/templates/default/module/dot/info.erb0000644000004100000410000000111612261240652021777 0ustar www-datawww-data<%= object.type %> <%= h object.name %> <% if options.full %> | <% object.attributes.each do |scope, list| %> <% list.sort_by {|name, rw| name.to_s }.each do |name, rw| %> <%= uml_visibility(rw.values.compact.first) %> <%= h (rw[:read]||rw[:write]).name(true).gsub(/=$/,'') %> [<%= 'R' if rw[:read] %><%= 'W' if rw[:write] %>]\l <% end %> <% end %> | <% method_listing.each do |obj| %> <%= uml_visibility obj %> <%= h obj.name(true) %> <%= h(" : #{obj.tag(:return).types.first}") if obj.has_tag?(:return) && obj.tag(:return).types && obj.tag(:return).types.size > 0 %>\l <% end %> <% end %>yard-0.8.7.3/templates/default/module/dot/child.erb0000644000004100000410000000012012261240652022121 0ustar www-datawww-data<%= format_path object %> [label="{<%= yieldall.gsub("\n", '') %>}" rank=sink]; yard-0.8.7.3/templates/default/module/dot/dependencies.erb0000644000004100000410000000021312261240652023467 0ustar www-datawww-data<% object.mixins(:instance).each do |obj| %> <%= format_path object %> -> <%= format_path obj %> [style=dotted arrowType=none]; <% end %>yard-0.8.7.3/templates/default/module/dot/setup.rb0000644000004100000410000000056712261240652022050 0ustar www-datawww-datadef init @modules = object.children.select {|o| o.type == :module } @classes = object.children.select {|o| o.type == :class } sections :child, [:info], :classes, [T('class')], :header, [T('module')], :dependencies end def dependencies return unless options.dependencies erb(:dependencies) end def classes @classes.map {|k| yieldall :object => k }.join("\n") endyard-0.8.7.3/templates/default/module/dot/header.erb0000644000004100000410000000030212261240652022270 0ustar www-datawww-datasubgraph cluster_<%= format_path object %> { label = "<%= h(object.name) unless object.path == "" %>"; labelloc=b; <% for obj in @modules %> <%= yieldall :object => obj %> <% end %> } yard-0.8.7.3/templates/default/module/setup.rb0000644000004100000410000001223012261240652021250 0ustar www-datawww-datainclude Helpers::ModuleHelper def init sections :header, :box_info, :pre_docstring, T('docstring'), :children, :constant_summary, [T('docstring')], :inherited_constants, :attribute_summary, [:item_summary], :inherited_attributes, :method_summary, [:item_summary], :inherited_methods, :methodmissing, [T('method_details')], :attribute_details, [T('method_details')], :method_details_list, [T('method_details')] end def pre_docstring return if object.docstring.blank? erb(:pre_docstring) end def children @inner = [[:modules, []], [:classes, []]] object.children.each do |child| @inner[0][1] << child if child.type == :module @inner[1][1] << child if child.type == :class end @inner.map! {|v| [v[0], run_verifier(v[1].sort_by {|o| o.name.to_s })] } return if (@inner[0][1].size + @inner[1][1].size) == 0 erb(:children) end def methodmissing mms = object.meths(:inherited => true, :included => true) return unless @mm = mms.find {|o| o.name == :method_missing && o.scope == :instance } erb(:methodmissing) end def method_listing(include_specials = true) return @smeths ||= method_listing.reject {|o| special_method?(o) } unless include_specials return @meths if @meths @meths = object.meths(:inherited => false, :included => !options.embed_mixins.empty?) if options.embed_mixins.size > 0 @meths = @meths.reject {|m| options.embed_mixins_match?(m.namespace) == false } end @meths = sort_listing(prune_method_listing(@meths)) @meths end def special_method?(meth) return true if meth.name(true) == '#method_missing' return true if meth.constructor? false end def attr_listing return @attrs if @attrs @attrs = [] object.inheritance_tree(true).each do |superclass| next if superclass.is_a?(CodeObjects::Proxy) next if options.embed_mixins.size > 0 && options.embed_mixins_match?(superclass) == false [:class, :instance].each do |scope| superclass.attributes[scope].each do |name, rw| attr = prune_method_listing([rw[:read], rw[:write]].compact, false).first @attrs << attr if attr end end break if options.embed_mixins.empty? end @attrs = sort_listing(@attrs) end def constant_listing return @constants if @constants @constants = object.constants(:included => false, :inherited => false) @constants += object.cvars @constants = run_verifier(@constants) @constants end def sort_listing(list) list.sort_by {|o| [o.scope.to_s, o.name.to_s.downcase] } end def inherited_attr_list(&block) object.inheritance_tree(true)[1..-1].each do |superclass| next if superclass.is_a?(YARD::CodeObjects::Proxy) next if options.embed_mixins.size > 0 && options.embed_mixins_match?(superclass) != false attribs = superclass.attributes[:instance] attribs = attribs.reject {|name, rw| object.child(:scope => :instance, :name => name) != nil } attribs = attribs.sort_by {|args| args.first.to_s }.map {|n, m| m[:read] || m[:write] } attribs = prune_method_listing(attribs, false) yield superclass, attribs if attribs.size > 0 end end def inherited_constant_list(&block) object.inheritance_tree(true)[1..-1].each do |superclass| next if superclass.is_a?(YARD::CodeObjects::Proxy) next if options.embed_mixins.size > 0 && options.embed_mixins_match?(superclass) != false consts = superclass.constants(:included => false, :inherited => false) consts = consts.reject {|const| object.child(:type => :constant, :name => const.name) != nil } consts = consts.sort_by {|const| const.name.to_s } consts = run_verifier(consts) yield superclass, consts if consts.size > 0 end end def docstring_full(obj) docstring = "" if obj.tags(:overload).size == 1 && obj.docstring.empty? docstring = obj.tag(:overload).docstring else docstring = obj.docstring end if docstring.summary.empty? && obj.tags(:return).size == 1 && obj.tag(:return).text docstring = Docstring.new(obj.tag(:return).text.gsub(/\A([a-z])/) {|x| x.upcase }.strip) end docstring end def docstring_summary(obj) docstring_full(obj).summary end def groups(list, type = "Method") if groups_data = object.groups list.each {|m| groups_data |= [m.group] if m.group && owner != m.namespace } others = list.select {|m| !m.group || !groups_data.include?(m.group) } groups_data.each do |name| items = list.select {|m| m.group == name } yield(items, name) unless items.empty? end else others = [] group_data = {} list.each do |meth| if meth.group (group_data[meth.group] ||= []) << meth else others << meth end end group_data.each {|group, items| yield(items, group) unless items.empty? } end scopes(others) {|items, scope| yield(items, "#{scope.to_s.capitalize} #{type} Summary") } end def scopes(list) [:class, :instance].each do |scope| items = list.select {|m| m.scope == scope } yield(items, scope) unless items.empty? end end def mixed_into(object) unless globals.mixed_into globals.mixed_into = {} list = run_verifier Registry.all(:class, :module) list.each {|o| o.mixins.each {|m| (globals.mixed_into[m.path] ||= []) << o } } end globals.mixed_into[object.path] || [] end yard-0.8.7.3/templates/default/onefile/0000755000004100000410000000000012261240652017721 5ustar www-datawww-datayard-0.8.7.3/templates/default/onefile/html/0000755000004100000410000000000012261240652020665 5ustar www-datawww-datayard-0.8.7.3/templates/default/onefile/html/headers.erb0000644000004100000410000000020012261240652022762 0ustar www-datawww-data yard-0.8.7.3/templates/default/onefile/html/readme.erb0000644000004100000410000000010712261240652022612 0ustar www-datawww-data
    <%= htmlify(parse_top_comments_from_file) %>
    yard-0.8.7.3/templates/default/onefile/html/files.erb0000644000004100000410000000015112261240652022456 0ustar www-datawww-data<% @files.each do |file| %> <% @file = file %>

    <%= file.title %>

    <%= diskfile %> <% end %>yard-0.8.7.3/templates/default/onefile/html/layout.erb0000644000004100000410000000075012261240652022676 0ustar www-datawww-data <%= @title %> <%= erb(:headers) %>

    <%= @title %>

    <%= yieldall %>
    <%= erb(:footer) %> yard-0.8.7.3/templates/default/onefile/html/setup.rb0000644000004100000410000000300012261240652022343 0ustar www-datawww-datainclude T('default/layout/html') include YARD::Parser::Ruby::Legacy def init override_serializer @object = YARD::Registry.root @files.shift @objects.delete(YARD::Registry.root) @objects.unshift(YARD::Registry.root) sections :layout, [:readme, :files, :all_objects] end def all_objects @objects.map {|obj| obj.format(options) }.join("\n") end def layout fulldoc = Object.new.extend(T('fulldoc')) layout = Object.new.extend(T('layout')) @css_data = layout.stylesheets.map {|sheet| read_asset(sheet) }.join("\n") @js_data = layout.javascripts.map {|script| read_asset(script) }.join("") erb(:layout) end def read_asset(file) return unless file = T('fulldoc').find_file(file) data = File.read(file) superfile = self.class.find_nth_file('fulldoc', 2) data.gsub!('{{{__super__}}}', superfile ? IO.read(superfile) : "") data end private def parse_top_comments_from_file return unless @readme return @readme.contents unless @readme.filename =~ /\.rb$/ data = "" tokens = TokenList.new(@readme.contents) tokens.each do |token| break unless token.is_a?(RubyToken::TkCOMMENT) || token.is_a?(RubyToken::TkNL) data << (token.text[/\A#\s{0,1}(.*)/, 1] || "\n") end YARD::Docstring.new(data) end def override_serializer return if @serializer.nil? class << @serializer def serialize(object, data) return unless object == 'index.html' super end def serialized_path(object) return object if object.is_a?(String) return 'index.html' end end endyard-0.8.7.3/templates/default/constant/0000755000004100000410000000000012261240652020131 5ustar www-datawww-datayard-0.8.7.3/templates/default/constant/text/0000755000004100000410000000000012261240652021115 5ustar www-datawww-datayard-0.8.7.3/templates/default/constant/text/setup.rb0000644000004100000410000000006212261240652022600 0ustar www-datawww-datadef init sections :header, [T('docstring')] end yard-0.8.7.3/templates/default/constant/text/header.erb0000644000004100000410000000030112261240652023031 0ustar www-datawww-data<%= title_align_right format_object_title(object) %> <%= object.name %> = <%= object.value.size > 40 ? "\n\n" + indent(object.value) : object.value %> <%= hr %> <%= yieldall %> <%= hr %> yard-0.8.7.3/templates/default/class/0000755000004100000410000000000012261240652017405 5ustar www-datawww-datayard-0.8.7.3/templates/default/class/html/0000755000004100000410000000000012261240652020351 5ustar www-datawww-datayard-0.8.7.3/templates/default/class/html/constructor_details.erb0000644000004100000410000000047512261240652025143 0ustar www-datawww-data

    Constructor Details

    <% if @ctor.namespace != object %>

    This class inherits a constructor from <%= linkify @ctor, @ctor.namespace.path %>

    <% else %> <%= yieldall :object => @ctor, :index => 0 %> <% end %>
    yard-0.8.7.3/templates/default/class/html/subclasses.erb0000644000004100000410000000024212261240652023210 0ustar www-datawww-data

    Direct Known Subclasses

    <%= @subclasses.map {|name, child| linkify(child, name) }.join(", ") %>

    yard-0.8.7.3/templates/default/class/html/setup.rb0000644000004100000410000000004012261240652022030 0ustar www-datawww-datainclude T('default/module/html')yard-0.8.7.3/templates/default/class/text/0000755000004100000410000000000012261240652020371 5ustar www-datawww-datayard-0.8.7.3/templates/default/class/text/subclasses.erb0000644000004100000410000000017212261240652023232 0ustar www-datawww-dataDirect Known Subclasses: ------------------------ <%= indent(wrap(@subclasses.map {|name, child| name }.join(", "))) %> yard-0.8.7.3/templates/default/class/text/setup.rb0000644000004100000410000000034012261240652022053 0ustar www-datawww-datainclude T('default/module/text') def init super sections.place(:subclasses).before(:children) sections.delete(:children) end def format_object_title(object) "Class: #{object.title} < #{object.superclass.title}" endyard-0.8.7.3/templates/default/class/dot/0000755000004100000410000000000012261240652020173 5ustar www-datawww-datayard-0.8.7.3/templates/default/class/dot/superklass.erb0000644000004100000410000000024512261240652023062 0ustar www-datawww-data<% if object.superclass.path != "Object" && object.superclass.path != "BasicObject" %> <%= format_path object %> -> <%= format_path object.superclass %>; <% end %>yard-0.8.7.3/templates/default/class/dot/setup.rb0000644000004100000410000000012112261240652021652 0ustar www-datawww-datainclude T('default/module/dot') def init super sections.push :superklass endyard-0.8.7.3/templates/default/class/setup.rb0000644000004100000410000000176312261240652021101 0ustar www-datawww-datainclude T('default/module') def init super sections.place(:subclasses).before(:children) sections.place(:constructor_details, [T('method_details')]).before(:methodmissing) end def constructor_details ctors = object.meths(:inherited => true, :included => true) return unless @ctor = ctors.find {|o| o.constructor? } return if prune_method_listing([@ctor]).empty? erb(:constructor_details) end def subclasses return if object.path == "Object" # don't show subclasses for Object unless globals.subclasses globals.subclasses = {} list = run_verifier Registry.all(:class) list.each do |o| (globals.subclasses[o.superclass.path] ||= []) << o if o.superclass end end @subclasses = globals.subclasses[object.path] return if @subclasses.nil? || @subclasses.empty? @subclasses = @subclasses.sort_by {|o| o.path }.map do |child| name = child.path if object.namespace name = object.relative_path(child) end [name, child] end erb(:subclasses) endyard-0.8.7.3/templates/default/layout/0000755000004100000410000000000012261240652017615 5ustar www-datawww-datayard-0.8.7.3/templates/default/layout/html/0000755000004100000410000000000012261240652020561 5ustar www-datawww-datayard-0.8.7.3/templates/default/layout/html/headers.erb0000644000004100000410000000102412261240652022663 0ustar www-datawww-data <%= h @page_title %> <% if options.title && @page_title != options.title %> — <%= h options.title %> <% end %> <% stylesheets.each do |stylesheet| %> <% end %> <%= erb :script_setup %> <% javascripts.each do |javascript| %> <% end %> yard-0.8.7.3/templates/default/layout/html/search.erb0000644000004100000410000000034512261240652022522 0ustar www-datawww-datayard-0.8.7.3/templates/default/layout/html/index.erb0000644000004100000410000000010512261240652022356 0ustar www-datawww-data

    <%= options.title %>

    <%= yieldall %> yard-0.8.7.3/templates/default/layout/html/script_setup.erb0000644000004100000410000000037112261240652024000 0ustar www-datawww-data yard-0.8.7.3/templates/default/layout/html/objects.erb0000644000004100000410000000160112261240652022702 0ustar www-datawww-data

    Namespace Listing A-Z

    <% if Registry.root.meths(:included => false).size > 0 %> <% end %> <% i = 0 %>
    <% @objects_by_letter.sort_by {|l,o| l.to_s }.each do |letter, objects| %> <% if (i += 1) % 8 == 0 %> <% i = 0 %> <% end %>
    • <%= letter %>
      • <% objects.each do |obj| %>
      • <%= linkify obj, obj.name %> <% if !obj.namespace.root? %> (<%= obj.namespace.path %>) <% end %>
      • <% end %>
    <% end %>
    yard-0.8.7.3/templates/default/layout/html/footer.erb0000644000004100000410000000033412261240652022551 0ustar www-datawww-data yard-0.8.7.3/templates/default/layout/html/files.erb0000644000004100000410000000045412261240652022360 0ustar www-datawww-data<% if @files && @files.size > 0 %>

    File Listing

    <% end %>
    yard-0.8.7.3/templates/default/layout/html/layout.erb0000644000004100000410000000075612261240652022600 0ustar www-datawww-data <%= erb(:headers) %>
    <%= yieldall %>
    <%= erb(:footer) %> yard-0.8.7.3/templates/default/layout/html/setup.rb0000644000004100000410000000361612261240652022254 0ustar www-datawww-datadef init @breadcrumb = [] if @onefile sections :layout elsif @file if @file.attributes[:namespace] @object = options.object = Registry.at(@file.attributes[:namespace]) || Registry.root end @breadcrumb_title = "File: " + @file.title @page_title = @breadcrumb_title sections :layout, [:diskfile] elsif @contents sections :layout, [:contents] else case object when '_index.html' @page_title = options.title sections :layout, [:index, [:listing, [:files, :objects]]] when CodeObjects::Base unless object.root? cur = object.namespace while !cur.root? @breadcrumb.unshift(cur) cur = cur.namespace end end @page_title = format_object_title(object) type = object.root? ? :module : object.type sections :layout, [T(type)] end end end def contents @contents end def index @objects_by_letter = {} objects = Registry.all(:class, :module).sort_by {|o| o.name.to_s } objects = run_verifier(objects) objects.each {|o| (@objects_by_letter[o.name.to_s[0,1].upcase] ||= []) << o } erb(:index) end def diskfile @file.attributes[:markup] ||= markup_for_file('', @file.filename) data = htmlify(@file.contents, @file.attributes[:markup]) "
    " + data + "
    " end # @return [Array] core javascript files for layout # @since 0.7.0 def javascripts %w(js/jquery.js js/app.js) end # @return [Array] core stylesheets for the layout # @since 0.7.0 def stylesheets %w(css/style.css css/common.css) end # @return [ArrayString}>] the list of search links and drop-down menus # @since 0.7.0 def menu_lists [ { :type => 'class', :title => 'Classes', :search_title => 'Class List' }, { :type => 'method', :title => 'Methods', :search_title => 'Method List' }, { :type => 'file', :title => 'Files', :search_title => 'File List' } ] end yard-0.8.7.3/templates/default/layout/html/listing.erb0000644000004100000410000000013312261240652022721 0ustar www-datawww-data

    Alphabetic Index

    <%= yieldall %>
    yard-0.8.7.3/templates/default/layout/html/breadcrumb.erb0000644000004100000410000000144412261240652023364 0ustar www-datawww-data yard-0.8.7.3/templates/default/layout/dot/0000755000004100000410000000000012261240652020403 5ustar www-datawww-datayard-0.8.7.3/templates/default/layout/dot/setup.rb0000644000004100000410000000032312261240652022066 0ustar www-datawww-dataattr_reader :contents def init if object type = object.root? ? :module : object.type sections :header, [T(type)] else sections :header, [:contents] end end def header tidy erb(:header) end yard-0.8.7.3/templates/default/layout/dot/header.erb0000644000004100000410000000024612261240652022327 0ustar www-datawww-datadigraph yard { graph [rankdir=BT rank=sink outputMode=nodesfirst packMode="graph" splines=true]; node [shape=record rank=sink rankType=sink]; <%= yieldall %> }yard-0.8.7.3/templates/default/method/0000755000004100000410000000000012261240652017560 5ustar www-datawww-datayard-0.8.7.3/templates/default/method/html/0000755000004100000410000000000012261240652020524 5ustar www-datawww-datayard-0.8.7.3/templates/default/method/html/header.erb0000644000004100000410000000066412261240652022454 0ustar www-datawww-data

    Method: <%= object.path %>

    Defined in:
    <%= object.file %><% if object.files.size > 1 %>,
    <%= object.files[1..-1].map {|f| f.first }.join(",
    ") %> <% end %>
    <%= yieldall :index => 0 %>
    yard-0.8.7.3/templates/default/method/text/0000755000004100000410000000000012261240652020544 5ustar www-datawww-datayard-0.8.7.3/templates/default/method/text/header.erb0000644000004100000410000000001712261240652022464 0ustar www-datawww-data<%= yieldall %>yard-0.8.7.3/templates/default/method/setup.rb0000644000004100000410000000006612261240652021247 0ustar www-datawww-datadef init sections :header, [T('method_details')] endyard-0.8.7.3/templates/default/fulldoc/0000755000004100000410000000000012261240652017730 5ustar www-datawww-datayard-0.8.7.3/templates/default/fulldoc/html/0000755000004100000410000000000012261240652020674 5ustar www-datawww-datayard-0.8.7.3/templates/default/fulldoc/html/full_list_file.erb0000644000004100000410000000023512261240652024362 0ustar www-datawww-data<% n = 1 %> <% @items.each do |item| %>
  • <%= link_file item %>
  • <% n = n == 2 ? 1 : 2 %> <% end %>yard-0.8.7.3/templates/default/fulldoc/html/js/0000755000004100000410000000000012261240652021310 5ustar www-datawww-datayard-0.8.7.3/templates/default/fulldoc/html/js/app.js0000644000004100000410000001541612261240652022435 0ustar www-datawww-datafunction createSourceLinks() { $('.method_details_list .source_code'). before("[View source]"); $('.toggleSource').toggle(function() { $(this).parent().nextAll('.source_code').slideDown(100); $(this).text("Hide source"); }, function() { $(this).parent().nextAll('.source_code').slideUp(100); $(this).text("View source"); }); } function createDefineLinks() { var tHeight = 0; $('.defines').after(" more..."); $('.toggleDefines').toggle(function() { tHeight = $(this).parent().prev().height(); $(this).prev().show(); $(this).parent().prev().height($(this).parent().height()); $(this).text("(less)"); }, function() { $(this).prev().hide(); $(this).parent().prev().height(tHeight); $(this).text("more..."); }); } function createFullTreeLinks() { var tHeight = 0; $('.inheritanceTree').toggle(function() { tHeight = $(this).parent().prev().height(); $(this).parent().toggleClass('showAll'); $(this).text("(hide)"); $(this).parent().prev().height($(this).parent().height()); }, function() { $(this).parent().toggleClass('showAll'); $(this).parent().prev().height(tHeight); $(this).text("show all"); }); } function fixBoxInfoHeights() { $('dl.box dd.r1, dl.box dd.r2').each(function() { $(this).prev().height($(this).height()); }); } function searchFrameLinks() { $('.full_list_link').click(function() { toggleSearchFrame(this, $(this).attr('href')); return false; }); } function toggleSearchFrame(id, link) { var frame = $('#search_frame'); $('#search a').removeClass('active').addClass('inactive'); if (frame.attr('src') == link && frame.css('display') != "none") { frame.slideUp(100); $('#search a').removeClass('active inactive'); } else { $(id).addClass('active').removeClass('inactive'); frame.attr('src', link).slideDown(100); } } function linkSummaries() { $('.summary_signature').click(function() { document.location = $(this).find('a').attr('href'); }); } function framesInit() { if (hasFrames) { document.body.className = 'frames'; $('#menu .noframes a').attr('href', document.location); try { window.top.document.title = $('html head title').text(); } catch(error) { // some browsers will not allow this when serving from file:// // but we don't want to stop the world. } } else { $('#menu .noframes a').text('frames').attr('href', framesUrl); } } function keyboardShortcuts() { if (window.top.frames.main) return; $(document).keypress(function(evt) { if (evt.altKey || evt.ctrlKey || evt.metaKey || evt.shiftKey) return; if (typeof evt.target !== "undefined" && (evt.target.nodeName == "INPUT" || evt.target.nodeName == "TEXTAREA")) return; switch (evt.charCode) { case 67: case 99: $('#class_list_link').click(); break; // 'c' case 77: case 109: $('#method_list_link').click(); break; // 'm' case 70: case 102: $('#file_list_link').click(); break; // 'f' default: break; } }); } function summaryToggle() { $('.summary_toggle').click(function() { if (localStorage) { localStorage.summaryCollapsed = $(this).text(); } $('.summary_toggle').each(function() { $(this).text($(this).text() == "collapse" ? "expand" : "collapse"); var next = $(this).parent().parent().nextAll('ul.summary').first(); if (next.hasClass('compact')) { next.toggle(); next.nextAll('ul.summary').first().toggle(); } else if (next.hasClass('summary')) { var list = $('
      '); list.html(next.html()); list.find('.summary_desc, .note').remove(); list.find('a').each(function() { $(this).html($(this).find('strong').html()); $(this).parent().html($(this)[0].outerHTML); }); next.before(list); next.toggle(); } }); return false; }); if (localStorage) { if (localStorage.summaryCollapsed == "collapse") { $('.summary_toggle').first().click(); } else localStorage.summaryCollapsed = "expand"; } } function fixOutsideWorldLinks() { $('a').each(function() { if (window.location.host != this.host) this.target = '_parent'; }); } function generateTOC() { if ($('#filecontents').length === 0) return; var _toc = $('
        '); var show = false; var toc = _toc; var counter = 0; var tags = ['h2', 'h3', 'h4', 'h5', 'h6']; var i; if ($('#filecontents h1').length > 1) tags.unshift('h1'); for (i = 0; i < tags.length; i++) { tags[i] = '#filecontents ' + tags[i]; } var lastTag = parseInt(tags[0][1], 10); $(tags.join(', ')).each(function() { if ($(this).parents('.method_details .docstring').length != 0) return; if (this.id == "filecontents") return; show = true; var thisTag = parseInt(this.tagName[1], 10); if (this.id.length === 0) { var proposedId = $(this).attr('toc-id'); if (typeof(proposedId) != "undefined") this.id = proposedId; else { var proposedId = $(this).text().replace(/[^a-z0-9-]/ig, '_'); if ($('#' + proposedId).length > 0) { proposedId += counter; counter++; } this.id = proposedId; } } if (thisTag > lastTag) { for (i = 0; i < thisTag - lastTag; i++) { var tmp = $('
          '); toc.append(tmp); toc = tmp; } } if (thisTag < lastTag) { for (i = 0; i < lastTag - thisTag; i++) toc = toc.parent(); } var title = $(this).attr('toc-title'); if (typeof(title) == "undefined") title = $(this).text(); toc.append('
        1. ' + title + '
        2. '); lastTag = thisTag; }); if (!show) return; html = ''; $('#content').prepend(html); $('#toc').append(_toc); $('#toc .hide_toc').toggle(function() { $('#toc .top').slideUp('fast'); $('#toc').toggleClass('hidden'); $('#toc .title small').toggle(); }, function() { $('#toc .top').slideDown('fast'); $('#toc').toggleClass('hidden'); $('#toc .title small').toggle(); }); $('#toc .float_toc').toggle(function() { $(this).text('float'); $('#toc').toggleClass('nofloat'); }, function() { $(this).text('left'); $('#toc').toggleClass('nofloat'); }); } $(framesInit); $(createSourceLinks); $(createDefineLinks); $(createFullTreeLinks); $(fixBoxInfoHeights); $(searchFrameLinks); $(linkSummaries); $(keyboardShortcuts); $(summaryToggle); $(fixOutsideWorldLinks); $(generateTOC); yard-0.8.7.3/templates/default/fulldoc/html/js/full_list.js0000644000004100000410000001236712261240652023654 0ustar www-datawww-datavar inSearch = null; var searchIndex = 0; var searchCache = []; var searchString = ''; var regexSearchString = ''; var caseSensitiveMatch = false; var ignoreKeyCodeMin = 8; var ignoreKeyCodeMax = 46; var commandKey = 91; RegExp.escape = function(text) { return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); } function fullListSearch() { // generate cache searchCache = []; $('#full_list li').each(function() { var link = $(this).find('.object_link a'); if (link.length === 0) return; var fullName = link.attr('title').split(' ')[0]; searchCache.push({name:link.text(), fullName:fullName, node:$(this), link:link}); }); $('#search input').keyup(function(event) { if ((event.keyCode > ignoreKeyCodeMin && event.keyCode < ignoreKeyCodeMax) || event.keyCode == commandKey) return; searchString = this.value; caseSensitiveMatch = searchString.match(/[A-Z]/) != null; regexSearchString = RegExp.escape(searchString); if (caseSensitiveMatch) { regexSearchString += "|" + $.map(searchString.split(''), function(e) { return RegExp.escape(e); }). join('.+?'); } if (searchString === "") { clearTimeout(inSearch); inSearch = null; $('ul .search_uncollapsed').removeClass('search_uncollapsed'); $('#full_list, #content').removeClass('insearch'); $('#full_list li').removeClass('found').each(function() { var link = $(this).find('.object_link a'); if (link.length > 0) link.text(link.text()); }); if (clicked) { clicked.parents('ul').each(function() { $(this).removeClass('collapsed').prev().removeClass('collapsed'); }); } highlight(); } else { if (inSearch) clearTimeout(inSearch); searchIndex = 0; lastRowClass = ''; $('#full_list, #content').addClass('insearch'); $('#noresults').text(''); searchItem(); } }); $('#search input').focus(); $('#full_list').after("
          "); } var lastRowClass = ''; function searchItem() { for (var i = 0; i < searchCache.length / 50; i++) { var item = searchCache[searchIndex]; var searchName = (searchString.indexOf('::') != -1 ? item.fullName : item.name); var matchString = regexSearchString; var matchRegexp = new RegExp(matchString, caseSensitiveMatch ? "" : "i"); if (searchName.match(matchRegexp) == null) { item.node.removeClass('found'); } else { item.node.css('padding-left', '10px').addClass('found'); item.node.parents().addClass('search_uncollapsed'); item.node.removeClass(lastRowClass).addClass(lastRowClass == 'r1' ? 'r2' : 'r1'); lastRowClass = item.node.hasClass('r1') ? 'r1' : 'r2'; item.link.html(item.name.replace(matchRegexp, "$&")); } if (searchCache.length === searchIndex + 1) { searchDone(); return; } else { searchIndex++; } } inSearch = setTimeout('searchItem()', 0); } function searchDone() { highlight(true); if ($('#full_list li:visible').size() === 0) { $('#noresults').text('No results were found.').hide().fadeIn(); } else { $('#noresults').text(''); } $('#content').removeClass('insearch'); clearTimeout(inSearch); inSearch = null; } clicked = null; function linkList() { $('#full_list li, #full_list li a:last').click(function(evt) { if ($(this).hasClass('toggle')) return true; if (this.tagName.toLowerCase() == "li") { if ($(this).find('.object_link a').length === 0) { $(this).children('a.toggle').click(); return false; } var toggle = $(this).children('a.toggle'); if (toggle.size() > 0 && evt.pageX < toggle.offset().left) { toggle.click(); return false; } } if (clicked) clicked.removeClass('clicked'); var win = window.top.frames.main ? window.top.frames.main : window.parent; if (this.tagName.toLowerCase() == "a") { clicked = $(this).parents('li').addClass('clicked'); win.location = this.href; } else { clicked = $(this).addClass('clicked'); win.location = $(this).find('a:last').attr('href'); } return false; }); } function collapse() { if (!$('#full_list').hasClass('class')) return; $('#full_list.class a.toggle').click(function() { $(this).parent().toggleClass('collapsed').next().toggleClass('collapsed'); highlight(); return false; }); $('#full_list.class ul').each(function() { $(this).addClass('collapsed').prev().addClass('collapsed'); }); $('#full_list.class').children().removeClass('collapsed'); highlight(); } function highlight(no_padding) { var n = 1; $('#full_list li:visible').each(function() { var next = n == 1 ? 2 : 1; $(this).removeClass("r" + next).addClass("r" + n); if (!no_padding && $('#full_list').hasClass('class')) { $(this).css('padding-left', (10 + $(this).parents('ul').size() * 15) + 'px'); } n = next; }); } function escapeShortcut() { $(document).keydown(function(evt) { if (evt.which == 27) { $('#search_frame', window.top.document).slideUp(100); $('#search a', window.top.document).removeClass('active inactive'); $(window.top).focus(); } }); } $(escapeShortcut); $(fullListSearch); $(linkList); $(collapse); yard-0.8.7.3/templates/default/fulldoc/html/js/jquery.js0000644000004100000410000026725412261240652023205 0ustar www-datawww-data/*! jQuery v1.7.1 jquery.com | jquery.org/license */ (function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"":"")+""),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;g=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
          a",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="
          "+""+"
          ",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="
          t
          ",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="
          ",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")}; f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&i.push({elem:this,matches:d.slice(e)});for(j=0;j0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

          ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
          ";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
          ","
          "],thead:[1,"","
          "],tr:[2,"","
          "],td:[3,"","
          "],col:[2,"","
          "],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
          ","
          "]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function() {for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
          ").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window);yard-0.8.7.3/templates/default/fulldoc/html/frames.erb0000644000004100000410000000167612261240652022655 0ustar www-datawww-data <%= options.title %> yard-0.8.7.3/templates/default/fulldoc/html/css/0000755000004100000410000000000012261240652021464 5ustar www-datawww-datayard-0.8.7.3/templates/default/fulldoc/html/css/full_list.css0000644000004100000410000001267512261240652024206 0ustar www-datawww-databody { margin: 0; font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; font-size: 13px; height: 101%; overflow-x: hidden; } h1 { padding: 12px 10px; padding-bottom: 0; margin: 0; font-size: 1.4em; } .clear { clear: both; } #search { position: absolute; right: 5px; top: 9px; padding-left: 24px; } #content.insearch #search, #content.insearch #noresults { background: url(data:image/gif;base64,R0lGODlhEAAQAPYAAP///wAAAPr6+pKSkoiIiO7u7sjIyNjY2J6engAAAI6OjsbGxjIyMlJSUuzs7KamppSUlPLy8oKCghwcHLKysqSkpJqamvT09Pj4+KioqM7OzkRERAwMDGBgYN7e3ujo6Ly8vCoqKjY2NkZGRtTU1MTExDw8PE5OTj4+PkhISNDQ0MrKylpaWrS0tOrq6nBwcKysrLi4uLq6ul5eXlxcXGJiYoaGhuDg4H5+fvz8/KKiohgYGCwsLFZWVgQEBFBQUMzMzDg4OFhYWBoaGvDw8NbW1pycnOLi4ubm5kBAQKqqqiQkJCAgIK6urnJyckpKSjQ0NGpqatLS0sDAwCYmJnx8fEJCQlRUVAoKCggICLCwsOTk5ExMTPb29ra2tmZmZmhoaNzc3KCgoBISEiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCAAAACwAAAAAEAAQAAAHaIAAgoMgIiYlg4kACxIaACEJCSiKggYMCRselwkpghGJBJEcFgsjJyoAGBmfggcNEx0flBiKDhQFlIoCCA+5lAORFb4AJIihCRbDxQAFChAXw9HSqb60iREZ1omqrIPdJCTe0SWI09GBACH5BAkIAAAALAAAAAAQABAAAAdrgACCgwc0NTeDiYozCQkvOTo9GTmDKy8aFy+NOBA7CTswgywJDTIuEjYFIY0JNYMtKTEFiRU8Pjwygy4ws4owPyCKwsMAJSTEgiQlgsbIAMrO0dKDGMTViREZ14kYGRGK38nHguHEJcvTyIEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDAggPg4iJAAMJCRUAJRIqiRGCBI0WQEEJJkWDERkYAAUKEBc4Po1GiKKJHkJDNEeKig4URLS0ICImJZAkuQAhjSi/wQyNKcGDCyMnk8u5rYrTgqDVghgZlYjcACTA1sslvtHRgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCQARAtOUoQRGRiFD0kJUYWZhUhKT1OLhR8wBaaFBzQ1NwAlkIszCQkvsbOHL7Y4q4IuEjaqq0ZQD5+GEEsJTDCMmIUhtgk1lo6QFUwJVDKLiYJNUd6/hoEAIfkECQgAAAAsAAAAABAAEAAAB2iAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4uen4ICCA+IkIsDCQkVACWmhwSpFqAABQoQF6ALTkWFnYMrVlhWvIKTlSAiJiVVPqlGhJkhqShHV1lCW4cMqSkAR1ofiwsjJyqGgQAh+QQJCAAAACwAAAAAEAAQAAAHZ4AAgoOEhYaCJSWHgxGDJCSMhREZGIYYGY2ElYebi56fhyWQniSKAKKfpaCLFlAPhl0gXYNGEwkhGYREUywag1wJwSkHNDU3D0kJYIMZQwk8MjPBLx9eXwuETVEyAC/BOKsuEjYFhoEAIfkECQgAAAAsAAAAABAAEAAAB2eAAIKDhIWGgiUlh4MRgyQkjIURGRiGGBmNhJWHm4ueICImip6CIQkJKJ4kigynKaqKCyMnKqSEK05StgAGQRxPYZaENqccFgIID4KXmQBhXFkzDgOnFYLNgltaSAAEpxa7BQoQF4aBACH5BAkIAAAALAAAAAAQABAAAAdogACCg4SFggJiPUqCJSWGgkZjCUwZACQkgxGEXAmdT4UYGZqCGWQ+IjKGGIUwPzGPhAc0NTewhDOdL7Ykji+dOLuOLhI2BbaFETICx4MlQitdqoUsCQ2vhKGjglNfU0SWmILaj43M5oEAOwAAAAAAAAAAAA==) no-repeat center left; } #full_list { padding: 0; list-style: none; margin-left: 0; } #full_list ul { padding: 0; } #full_list li { padding: 5px; padding-left: 12px; margin: 0; font-size: 1.1em; list-style: none; } #noresults { padding: 7px 12px; } #content.insearch #noresults { margin-left: 7px; } ul.collapsed ul, ul.collapsed li { display: none; } ul.collapsed.search_uncollapsed { display: block; } ul.collapsed.search_uncollapsed li { display: list-item; } li a.toggle { cursor: default; position: relative; left: -5px; top: 4px; text-indent: -999px; width: 10px; height: 9px; margin-left: -10px; display: block; float: left; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAASCAYAAABb0P4QAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAK8AAACvABQqw0mAAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTM5jWRgMAAAAVdEVYdENyZWF0aW9uIFRpbWUAMy8xNC8wOeNZPpQAAAE2SURBVDiNrZTBccIwEEXfelIAHUA6CZ24BGaWO+FuzZAK4k6gg5QAdGAq+Bxs2Yqx7BzyL7Llp/VfzZeQhCTc/ezuGzKKnKSzpCxXJM8fwNXda3df5RZETlIt6YUzSQDs93sl8w3wBZxCCE10GM1OcWbWjB2mWgEH4Mfdyxm3PSepBHibgQE2wLe7r4HjEidpnXMYdQPKEMJcsZ4zs2POYQOcaPfwMVOo58zsAdMt18BuoVDPxUJRacELbXv3hUIX2vYmOUvi8C8ydz/ThjXrqKqqLbDIAdsCKBd+Wo7GWa7o9qzOQHVVVXeAbs+yHHCH4aTsaCOQqunmUy1yBUAXkdMIfMlgF5EXLo2OpV/c/Up7jG4hhHcYLgWzAZXUc2b2ixsfvc/RmNNfOXD3Q/oeL9axJE1yT9IOoUu6MGUkAAAAAElFTkSuQmCC) no-repeat bottom left; } li.collapsed a.toggle { opacity: 0.5; cursor: default; background-position: top left; } li { color: #888; cursor: pointer; } li.deprecated { text-decoration: line-through; font-style: italic; } li.r1 { background: #f0f0f0; } li.r2 { background: #fafafa; } li:hover { background: #ddd; } li small:before { content: "("; } li small:after { content: ")"; } li small.search_info { display: none; } a:link, a:visited { text-decoration: none; color: #05a; } li.clicked { background: #05a; color: #ccc; } li.clicked a:link, li.clicked a:visited { color: #eee; } li.clicked a.toggle { opacity: 0.5; background-position: bottom right; } li.collapsed.clicked a.toggle { background-position: top right; } #search input { border: 1px solid #bbb; -moz-border-radius: 3px; -webkit-border-radius: 3px; } #nav { margin-left: 10px; font-size: 0.9em; display: none; color: #aaa; } #nav a:link, #nav a:visited { color: #358; } #nav a:hover { background: transparent; color: #5af; } .frames #nav span:after { content: ' | '; } .frames #nav span:last-child:after { content: ''; } .frames #content h1 { margin-top: 0; } .frames li { white-space: nowrap; cursor: normal; } .frames li small { display: block; font-size: 0.8em; } .frames li small:before { content: ""; } .frames li small:after { content: ""; } .frames li small.search_info { display: none; } .frames #search { width: 170px; position: static; margin: 3px; margin-left: 10px; font-size: 0.9em; color: #888; padding-left: 0; padding-right: 24px; } .frames #content.insearch #search { background-position: center right; } .frames #search input { width: 110px; } .frames #nav { display: block; } #full_list.insearch li { display: none; } #full_list.insearch li.found { display: list-item; padding-left: 10px; } #full_list.insearch li a.toggle { display: none; } #full_list.insearch li small.search_info { display: block; } yard-0.8.7.3/templates/default/fulldoc/html/css/common.css0000644000004100000410000000005212261240652023463 0ustar www-datawww-data/* Override this file with custom rules */yard-0.8.7.3/templates/default/fulldoc/html/css/style.css0000644000004100000410000004264412261240652023350 0ustar www-datawww-databody { padding: 0 20px; font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; font-size: 13px; } body.frames { padding: 0 5px; } h1 { font-size: 25px; margin: 1em 0 0.5em; padding-top: 4px; border-top: 1px dotted #d5d5d5; } h1.noborder { border-top: 0px; margin-top: 0; padding-top: 4px; } h1.title { margin-bottom: 10px; } h1.alphaindex { margin-top: 0; font-size: 22px; } h2 { padding: 0; padding-bottom: 3px; border-bottom: 1px #aaa solid; font-size: 1.4em; margin: 1.8em 0 0.5em; } h2 small { font-weight: normal; font-size: 0.7em; display: block; float: right; } .clear { clear: both; } .inline { display: inline; } .inline p:first-child { display: inline; } .docstring h1, .docstring h2, .docstring h3, .docstring h4 { padding: 0; border: 0; border-bottom: 1px dotted #bbb; } .docstring h1 { font-size: 1.2em; } .docstring h2 { font-size: 1.1em; } .docstring h3, .docstring h4 { font-size: 1em; border-bottom: 0; padding-top: 10px; } .summary_desc .object_link, .docstring .object_link { font-family: monospace; } .rdoc-term { padding-right: 25px; font-weight: bold; } .rdoc-list p { margin: 0; padding: 0; margin-bottom: 4px; } /* style for
          */ #filecontents table, .docstring table { border-collapse: collapse; } #filecontents table th, #filecontents table td, .docstring table th, .docstring table td { border: 1px solid #ccc; padding: 8px; padding-right: 17px; } #filecontents table tr:nth-child(odd), .docstring table tr:nth-child(odd) { background: #eee; } #filecontents table tr:nth-child(even), .docstring table tr:nth-child(even) { background: #fff; } #filecontents table th, .docstring table th { background: #fff; } /* style for
            */ #filecontents li > p, .docstring li > p { margin: 0px; } #filecontents ul, .docstring ul { padding-left: 20px; } /* style for
            */ #filecontents dl, .docstring dl { border: 1px solid #ccc; } #filecontents dt, .docstring dt { background: #ddd; font-weight: bold; padding: 3px 5px; } #filecontents dd, .docstring dd { padding: 5px 0px; margin-left: 18px; } #filecontents dd > p, .docstring dd > p { margin: 0px; } .note { color: #222; -moz-border-radius: 3px; -webkit-border-radius: 3px; background: #e3e4e3; border: 1px solid #d5d5d5; padding: 7px 10px; display: block; } .note.todo { background: #ffffc5; border-color: #ececaa; } .note.returns_void { background: #efefef; } .note.deprecated { background: #ffe5e5; border-color: #e9dada; } .note.private { background: #ffffc5; border-color: #ececaa; } .note.title { padding: 1px 5px; font-size: 0.9em; font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; display: inline; } .summary_signature + .note.title { margin-left: 7px; } h1 .note.title { font-size: 0.5em; font-weight: normal; padding: 3px 5px; position: relative; top: -3px; text-transform: capitalize; } .note.title.constructor { color: #fff; background: #6a98d6; border-color: #6689d6; } .note.title.writeonly { color: #fff; background: #45a638; border-color: #2da31d; } .note.title.readonly { color: #fff; background: #6a98d6; border-color: #6689d6; } .note.title.private { background: #d5d5d5; border-color: #c5c5c5; } .note.title.not_defined_here { background: transparent; border: none; font-style: italic; } .discussion .note { margin-top: 6px; } .discussion .note:first-child { margin-top: 0; } h3.inherited { font-style: italic; font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; font-weight: normal; padding: 0; margin: 0; margin-top: 12px; margin-bottom: 3px; font-size: 13px; } p.inherited { padding: 0; margin: 0; margin-left: 25px; } #filecontents dl.box, dl.box { border: 0; width: 520px; font-size: 1em; } #filecontents dl.box dt, dl.box dt { float: left; display: block; width: 100px; margin: 0; text-align: right; font-weight: bold; background: transparent; border: 1px solid #aaa; border-width: 1px 0px 0px 1px; padding: 6px 0; padding-right: 10px; } #filecontents dl.box dd, dl.box dd { float: left; display: block; width: 380px; margin: 0; padding: 6px 0; padding-right: 20px; border: 1px solid #aaa; border-width: 1px 1px 0 0; } #filecontents dl.box .last, dl.box .last { border-bottom: 1px solid #aaa; } #filecontents dl.box .r1, dl.box .r1 { background: #eee; } ul.toplevel { list-style: none; padding-left: 0; font-size: 1.1em; } .index_inline_list { padding-left: 0; font-size: 1.1em; } .index_inline_list li { list-style: none; display: inline; padding: 7px 12px; line-height: 35px; } dl.constants { margin-left: 40px; } dl.constants dt { font-weight: bold; font-size: 1.1em; margin-bottom: 5px; } dl.constants dd { width: 75%; white-space: pre; font-family: monospace; margin-bottom: 18px; } .summary_desc { margin-left: 32px; display: block; font-family: sans-serif; } .summary_desc tt { font-size: 0.9em; } dl.constants .note { padding: 2px 6px; padding-right: 12px; margin-top: 6px; } dl.constants .docstring { margin-left: 32px; font-size: 0.9em; font-weight: normal; } dl.constants .tags { padding-left: 32px; font-size: 0.9em; line-height: 0.8em; } dl.constants .discussion *:first-child { margin-top: 0; } dl.constants .discussion *:last-child { margin-bottom: 0; } .method_details { border-top: 1px dotted #aaa; margin-top: 15px; padding-top: 0; } .method_details.first { border: 0; } p.signature, h3.signature { font-size: 1.1em; font-weight: normal; font-family: Monaco, Consolas, Courier, monospace; padding: 6px 10px; margin-top: 18px; background: #e5e8ff; border: 1px solid #d8d8e5; -moz-border-radius: 3px; -webkit-border-radius: 3px; } p.signature tt, h3.signature tt { font-family: Monaco, Consolas, Courier, monospace; } p.signature .overload, h3.signature .overload { display: block; } p.signature .extras, h3.signature .extras { font-weight: normal; font-family: sans-serif; color: #444; font-size: 1em; } p.signature .not_defined_here, h3.signature .not_defined_here, p.signature .aliases, h3.signature .aliases { display: block; font-weight: normal; font-size: 0.9em; font-family: sans-serif; margin-top: 0px; color: #555; } p.signature .aliases .names, h3.signature .aliases .names { font-family: Monaco, Consolas, Courier, monospace; font-weight: bold; color: #000; font-size: 1.2em; } .tags .tag_title { font-size: 1em; margin-bottom: 0; font-weight: bold; } .tags ul { margin-top: 5px; padding-left: 30px; list-style: square; } .tags ul li { margin-bottom: 3px; } .tags ul .name { font-family: monospace; font-weight: bold; } .tags ul .note { padding: 3px 6px; } .tags { margin-bottom: 12px; } .tags .examples .tag_title { margin-bottom: 10px; font-weight: bold; } .tags .examples .inline p { padding: 0; margin: 0; margin-left: 15px; font-weight: bold; font-size: 0.9em; } .tags .overload .overload_item { list-style: none; margin-bottom: 25px; } .tags .overload .overload_item .signature { padding: 2px 8px; background: #e5e8ff; border: 1px solid #d8d8e5; -moz-border-radius: 3px; -webkit-border-radius: 3px; } .tags .overload .signature { margin-left: -15px; font-family: monospace; display: block; font-size: 1.1em; } .tags .overload .docstring { margin-top: 15px; } .defines { display: none; } #method_missing_details .notice.this { position: relative; top: -8px; color: #888; padding: 0; margin: 0; } .showSource { font-size: 0.9em; } .showSource a:link, .showSource a:visited { text-decoration: none; color: #666; } #content a:link, #content a:visited { text-decoration: none; color: #05a; } #content a:hover { background: #ffffa5; } div.docstring, p.docstring { margin-right: 6em; } ul.summary { list-style: none; font-family: monospace; font-size: 1em; line-height: 1.5em; } ul.summary a:link, ul.summary a:visited { text-decoration: none; font-size: 1.1em; } ul.summary li { margin-bottom: 5px; } .summary .summary_signature { padding: 1px 10px; background: #eaeaff; border: 1px solid #dfdfe5; -moz-border-radius: 3px; -webkit-border-radius: 3px; } .summary_signature:hover { background: #eeeeff; cursor: pointer; } ul.summary.compact li { display: inline-block; margin: 0px 5px 0px 0px; line-height: 2.6em;} ul.summary.compact .summary_signature { padding: 5px 7px; padding-right: 4px; } #content .summary_signature:hover a:link, #content .summary_signature:hover a:visited { background: transparent; color: #48f; } p.inherited a { font-family: monospace; font-size: 0.9em; } p.inherited { word-spacing: 5px; font-size: 1.2em; } p.children { font-size: 1.2em; } p.children a { font-size: 0.9em; } p.children strong { font-size: 0.8em; } p.children strong.modules { padding-left: 5px; } ul.fullTree { display: none; padding-left: 0; list-style: none; margin-left: 0; margin-bottom: 10px; } ul.fullTree ul { margin-left: 0; padding-left: 0; list-style: none; } ul.fullTree li { text-align: center; padding-top: 18px; padding-bottom: 12px; background: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAAAHtJREFUeNqMzrEJAkEURdGzuhgZbSoYWcAWoBVsB4JgZAGmphsZCZYzTQgWNCYrDN9RvMmHx+X916SUBFbo8CzD1idXrLErw1mQttgXtyrOcQ/Ny5p4Qh+2XqLYYazsPWNTiuMkRxa4vcV+evuNAUOLIx5+c2hyzv7hNQC67Q+/HHmlEwAAAABJRU5ErkJggg==) no-repeat top center; } ul.fullTree li:first-child { padding-top: 0; background: transparent; } ul.fullTree li:last-child { padding-bottom: 0; } .showAll ul.fullTree { display: block; } .showAll .inheritName { display: none; } #search { position: absolute; right: 14px; top: 0px; } #search a:link, #search a:visited { display: block; float: left; margin-right: 4px; padding: 8px 10px; text-decoration: none; color: #05a; border: 1px solid #d8d8e5; -moz-border-radius-bottomleft: 3px; -moz-border-radius-bottomright: 3px; -webkit-border-bottom-left-radius: 3px; -webkit-border-bottom-right-radius: 3px; background: #eaf0ff; -webkit-box-shadow: -1px 1px 3px #ddd; } #search a:hover { background: #f5faff; color: #06b; } #search a.active { background: #568; padding-bottom: 20px; color: #fff; border: 1px solid #457; -moz-border-radius-topleft: 5px; -moz-border-radius-topright: 5px; -webkit-border-top-left-radius: 5px; -webkit-border-top-right-radius: 5px; } #search a.inactive { color: #999; } .frames #search { display: none; } .inheritanceTree, .toggleDefines { float: right; } #menu { font-size: 1.3em; color: #bbb; top: -5px; position: relative; } #menu .title, #menu a { font-size: 0.7em; } #menu .title a { font-size: 1em; } #menu .title { color: #555; } #menu a:link, #menu a:visited { color: #333; text-decoration: none; border-bottom: 1px dotted #bbd; } #menu a:hover { color: #05a; } #menu .noframes { display: inline; } .frames #menu .noframes { display: inline; float: right; } #footer { margin-top: 15px; border-top: 1px solid #ccc; text-align: center; padding: 7px 0; color: #999; } #footer a:link, #footer a:visited { color: #444; text-decoration: none; border-bottom: 1px dotted #bbd; } #footer a:hover { color: #05a; } #listing ul.alpha { font-size: 1.1em; } #listing ul.alpha { margin: 0; padding: 0; padding-bottom: 10px; list-style: none; } #listing ul.alpha li.letter { font-size: 1.4em; padding-bottom: 10px; } #listing ul.alpha ul { margin: 0; padding-left: 15px; } #listing ul small { color: #666; font-size: 0.7em; } li.r1 { background: #f0f0f0; } li.r2 { background: #fafafa; } #search_frame { z-index: 9999; background: #fff; display: none; position: absolute; top: 36px; right: 18px; width: 500px; height: 80%; overflow-y: scroll; border: 1px solid #999; border-collapse: collapse; -webkit-box-shadow: -7px 5px 25px #aaa; -moz-box-shadow: -7px 5px 25px #aaa; -moz-border-radius: 2px; -webkit-border-radius: 2px; } #content ul.summary li.deprecated .summary_signature a:link, #content ul.summary li.deprecated .summary_signature a:visited { text-decoration: line-through; font-style: italic; } #toc { padding: 20px; padding-right: 30px; border: 1px solid #ddd; float: right; background: #fff; margin-left: 20px; margin-bottom: 20px; max-width: 300px; -webkit-box-shadow: -2px 2px 6px #bbb; -moz-box-shadow: -2px 2px 6px #bbb; z-index: 5000; position: relative; } #toc.nofloat { float: none; max-width: none; border: none; padding: 0; margin: 20px 0; -webkit-box-shadow: none; -moz-box-shadow: none; } #toc.nofloat.hidden { padding: 0; background: 0; margin-bottom: 5px; } #toc .title { margin: 0; } #toc ol { padding-left: 1.8em; } #toc li { font-size: 1.1em; line-height: 1.7em; } #toc > ol > li { font-size: 1.1em; font-weight: bold; } #toc ol > ol { font-size: 0.9em; } #toc ol ol > ol { padding-left: 2.3em; } #toc ol + li { margin-top: 0.3em; } #toc.hidden { padding: 10px; background: #f6f6f6; -webkit-box-shadow: none; -moz-box-shadow: none; } #filecontents h1 + #toc.nofloat { margin-top: 0; } /* syntax highlighting */ .source_code { display: none; padding: 3px 8px; border-left: 8px solid #ddd; margin-top: 5px; } #filecontents pre.code, .docstring pre.code, .source_code pre { font-family: monospace; } #filecontents pre.code, .docstring pre.code { display: block; } .source_code .lines { padding-right: 12px; color: #555; text-align: right; } #filecontents pre.code, .docstring pre.code, .tags pre.example { padding: 5px 12px; margin-top: 4px; border: 1px solid #eef; background: #f5f5ff; } pre.code { color: #000; } pre.code .info.file { color: #555; } pre.code .val { color: #036A07; } pre.code .tstring_content, pre.code .heredoc_beg, pre.code .heredoc_end, pre.code .qwords_beg, pre.code .qwords_end, pre.code .tstring, pre.code .dstring { color: #036A07; } pre.code .fid, pre.code .rubyid_new, pre.code .rubyid_to_s, pre.code .rubyid_to_sym, pre.code .rubyid_to_f, pre.code .dot + pre.code .id, pre.code .rubyid_to_i pre.code .rubyid_each { color: #0085FF; } pre.code .comment { color: #0066FF; } pre.code .const, pre.code .constant { color: #585CF6; } pre.code .label, pre.code .symbol { color: #C5060B; } pre.code .kw, pre.code .rubyid_require, pre.code .rubyid_extend, pre.code .rubyid_include { color: #0000FF; } pre.code .ivar { color: #318495; } pre.code .gvar, pre.code .rubyid_backref, pre.code .rubyid_nth_ref { color: #6D79DE; } pre.code .regexp, .dregexp { color: #036A07; } pre.code a { border-bottom: 1px dotted #bbf; } yard-0.8.7.3/templates/default/fulldoc/html/full_list_class.erb0000644000004100000410000000013612261240652024550 0ustar www-datawww-data
          • <%= link_object(Registry.root, Registry.root.title, nil, false) %>
          • <%= class_list %> yard-0.8.7.3/templates/default/fulldoc/html/full_list.erb0000644000004100000410000000257212261240652023371 0ustar www-datawww-data <% stylesheets_full_list.each do |stylesheet| %> <% end %> <% javascripts_full_list.each do |javascript| %> <% end %> <%= @list_title %>

            <%= @list_title %>

              <%= erb "full_list_#{@list_type}" %>
            yard-0.8.7.3/templates/default/fulldoc/html/full_list_method.erb0000644000004100000410000000037612261240652024731 0ustar www-datawww-data<% n = 1 %> <% @items.each do |item| %>
          • <%= linkify item, h(item.name(true)) %> <%= item.namespace.title %>
          • <% n = n == 2 ? 1 : 2 %> <% end %>yard-0.8.7.3/templates/default/fulldoc/html/setup.rb0000644000004100000410000001374012261240652022366 0ustar www-datawww-datainclude Helpers::ModuleHelper def init options.objects = objects = run_verifier(options.objects) return serialize_onefile if options.onefile generate_assets serialize('_index.html') options.files.each_with_index do |file, i| serialize_file(file, file.title) end options.delete(:objects) options.delete(:files) objects.each do |object| begin serialize(object) rescue => e path = options.serializer.serialized_path(object) log.error "Exception occurred while generating '#{path}'" log.backtrace(e) end end end # Generate an HTML document for the specified object. This method is used by # most of the objects found in the Registry. # @param [CodeObject] object to be saved to HTML def serialize(object) options.object = object serialize_index(options) if object == '_index.html' && options.files.empty? Templates::Engine.with_serializer(object, options.serializer) do T('layout').run(options) end end # Generate the documentation output in one file (--one-file) which will load the # contents of all the javascript and css and output the entire contents without # depending on any additional files def serialize_onefile Templates::Engine.with_serializer('index.html', options.serializer) do T('onefile').run(options) end end # Generate the index document for the output # @params [Hash] options contains data and flags that influence the output def serialize_index(options) Templates::Engine.with_serializer('index.html', options.serializer) do T('layout').run(options) end end # Generate a single HTML file with the layout template applied. This is generally # the README file or files specified on the command-line. # # @param [File] file object to be saved to the output # @param [String] title currently unused # # @see layout#diskfile def serialize_file(file, title = nil) options.object = Registry.root options.file = file outfile = 'file.' + file.name + '.html' serialize_index(options) if file == options.readme Templates::Engine.with_serializer(outfile, options.serializer) do T('layout').run(options) end options.delete(:file) end # # Generates a file to the output with the specified contents. # # @example saving a custom html file to the documenation root # # asset('my_custom.html','Custom File') # # @param [String] path relative to the document output where the file will be # created. # @param [String] content the contents that are saved to the file. def asset(path, content) if options.serializer log.capture("Generating asset #{path}") do options.serializer.serialize(path, content) end end end # @return [Array] Stylesheet files that are additionally loaded for the # searchable full lists, e.g., Class List, Method List, File List # @since 0.7.0 def stylesheets_full_list %w(css/full_list.css css/common.css) end # @return [Array] Javascript files that are additionally loaded for the # searchable full lists, e.g., Class List, Method List, File List. # @since 0.7.0 def javascripts_full_list %w(js/jquery.js js/full_list.js) end def menu_lists Object.new.extend(T('layout')).menu_lists end # Generates all the javascript files, stylesheet files, menu lists # (i.e. class, method, and file) based on the the values returned from the # layout's menu_list method, and the frameset in the documentation output # def generate_assets @object = Registry.root layout = Object.new.extend(T('layout')) (layout.javascripts + javascripts_full_list + layout.stylesheets + stylesheets_full_list).uniq.each do |file| asset(file, file(file, true)) end layout.menu_lists.each do |list| list_generator_method = "generate_#{list[:type]}_list" if respond_to?(list_generator_method) send(list_generator_method) else log.error "Unable to generate '#{list[:title]}' list because no method " + "'#{list_generator_method}' exists" end end generate_frameset end # Generate a searchable method list in the output # @see ModuleHelper#prune_method_listing def generate_method_list @items = prune_method_listing(Registry.all(:method), false) @items = @items.reject {|m| m.name.to_s =~ /=$/ && m.is_attribute? } @items = @items.sort_by {|m| m.name.to_s } @list_title = "Method List" @list_type = "method" generate_list_contents end # Generate a searchable class list in the output def generate_class_list @items = options.objects if options.objects @list_title = "Class List" @list_type = "class" generate_list_contents end # Generate a searchable file list in the output def generate_file_list @file_list = true @items = options.files @list_title = "File List" @list_type = "file" generate_list_contents @file_list = nil end def generate_list_contents asset(url_for_list(@list_type), erb(:full_list)) end # Generate the frame documentation in the output def generate_frameset @javascripts = javascripts_full_list @stylesheets = stylesheets_full_list asset(url_for_frameset, erb(:frames)) end # @return [String] HTML output of the classes to be displayed in the # full_list_class template. def class_list(root = Registry.root) out = "" children = run_verifier(root.children) if root == Registry.root children += @items.select {|o| o.namespace.is_a?(CodeObjects::Proxy) } end children.reject {|c| c.nil? }.sort_by {|child| child.path }.map do |child| if child.is_a?(CodeObjects::NamespaceObject) name = child.namespace.is_a?(CodeObjects::Proxy) ? child.path : child.name has_children = run_verifier(child.children).any? {|o| o.is_a?(CodeObjects::NamespaceObject) } out << "
          • " out << " " if has_children out << linkify(child, name) out << " < #{child.superclass.name}" if child.is_a?(CodeObjects::ClassObject) && child.superclass out << "" out << child.namespace.title out << "" out << "
          • " out << "
              #{class_list(child)}
            " if has_children end end out endyard-0.8.7.3/templates/guide/0000755000004100000410000000000012261240652015751 5ustar www-datawww-datayard-0.8.7.3/templates/guide/tags/0000755000004100000410000000000012261240652016707 5ustar www-datawww-datayard-0.8.7.3/templates/guide/tags/html/0000755000004100000410000000000012261240652017653 5ustar www-datawww-datayard-0.8.7.3/templates/guide/tags/html/setup.rb0000644000004100000410000000021412261240652021335 0ustar www-datawww-datainclude T('default/tags/html') def init super [:since, :see, :return].each do |section| sections[:index].delete(section) end end yard-0.8.7.3/templates/guide/docstring/0000755000004100000410000000000012261240652017745 5ustar www-datawww-datayard-0.8.7.3/templates/guide/docstring/html/0000755000004100000410000000000012261240652020711 5ustar www-datawww-datayard-0.8.7.3/templates/guide/docstring/html/setup.rb0000644000004100000410000000004412261240652022374 0ustar www-datawww-datainclude T('default/docstring/html') yard-0.8.7.3/templates/guide/module/0000755000004100000410000000000012261240652017236 5ustar www-datawww-datayard-0.8.7.3/templates/guide/module/html/0000755000004100000410000000000012261240652020202 5ustar www-datawww-datayard-0.8.7.3/templates/guide/module/html/method_list.erb0000644000004100000410000000024112261240652023204 0ustar www-datawww-data
            <% @meths.each_with_index do |meth, i| %> <%= yieldall(:object => meth, :index => i, :in_module => true) %> <% end %>
            yard-0.8.7.3/templates/guide/module/html/setup.rb0000644000004100000410000000132612261240652021671 0ustar www-datawww-datainclude Helpers::ModuleHelper def init sections :header, [T('docstring')], :method_list, [T('method')] end def method_list @meths = object.meths(:inherited => false, :included => false) cons = @meths.find {|meth| meth.constructor? } @meths = @meths.reject {|meth| special_method?(meth) } @meths = sort_listing(prune_method_listing(@meths, false)) @meths.unshift(cons) if cons erb(:method_list) end def sort_listing(list) list.sort_by {|o| [o.scope.to_s, o.name.to_s.downcase] } end def special_method?(meth) return true if meth.writer? && meth.attr_info[:read] return true if meth.name(true) == 'new' return true if meth.name(true) == '#method_missing' return true if meth.constructor? false end yard-0.8.7.3/templates/guide/module/html/header.erb0000644000004100000410000000055312261240652022127 0ustar www-datawww-data
            <%= object.type %> <%= object.namespace == Registry.root ? '' : object.namespace.path + '::' %><%= object.name %> <% if object.has_tag?(:since) %>since <%= object.tag(:since).text %><% end %>
            <%= yieldall %>
            yard-0.8.7.3/templates/guide/onefile/0000755000004100000410000000000012261240652017372 5ustar www-datawww-datayard-0.8.7.3/templates/guide/onefile/html/0000755000004100000410000000000012261240652020336 5ustar www-datawww-datayard-0.8.7.3/templates/guide/onefile/html/toc.erb0000644000004100000410000000013012261240652021607 0ustar www-datawww-data

            <%= @title %>

            Table of Contents

            yard-0.8.7.3/templates/guide/onefile/html/files.erb0000644000004100000410000000011512261240652022127 0ustar www-datawww-data<% @files.each do |file| %> <% @file = file %> <%= diskfile %> <% end %> yard-0.8.7.3/templates/guide/onefile/html/setup.rb0000644000004100000410000000012312261240652022017 0ustar www-datawww-datainclude T('default/onefile/html') def init sections :layout, [:toc, :files] end yard-0.8.7.3/templates/guide/class/0000755000004100000410000000000012261240652017056 5ustar www-datawww-datayard-0.8.7.3/templates/guide/class/html/0000755000004100000410000000000012261240652020022 5ustar www-datawww-datayard-0.8.7.3/templates/guide/class/html/setup.rb0000644000004100000410000000003712261240652021507 0ustar www-datawww-datainclude T('guide/module/html') yard-0.8.7.3/templates/guide/layout/0000755000004100000410000000000012261240652017266 5ustar www-datawww-datayard-0.8.7.3/templates/guide/layout/html/0000755000004100000410000000000012261240652020232 5ustar www-datawww-datayard-0.8.7.3/templates/guide/layout/html/layout.erb0000644000004100000410000000415412261240652022245 0ustar www-datawww-data <%= erb(:headers) %>
            <% if options.readme != options.file && options.title %> <%= options.title %>: <%= @page_title %> <% links = [@prevfile ? link_file(@prevfile, '←') : nil, link_file('index.html', '↑'), @nextfile ? link_file(@nextfile, '→') : nil].compact %> <%= links.join(" ") %> <% end %>
            <%= yieldall %>
            <%= erb(:footer) %> yard-0.8.7.3/templates/guide/layout/html/setup.rb0000644000004100000410000000107112261240652021716 0ustar www-datawww-datainclude T('default/layout/html') def init super @topfile = options.readme if options.files if @topfile @toptitle = @topfile.attributes[:title] || "Documentation Overview" end if @file == options.readme @page_title = options.title else @page_title = @file.title end index = options.files.index(@file) if index @prevfile = index > 0 ? (options.files[index - 1] || options.readme) : nil @nextfile = options.files[index + 1] end end end def diskfile options.including_object = @object super end yard-0.8.7.3/templates/guide/method/0000755000004100000410000000000012261240652017231 5ustar www-datawww-datayard-0.8.7.3/templates/guide/method/html/0000755000004100000410000000000012261240652020175 5ustar www-datawww-datayard-0.8.7.3/templates/guide/method/html/setup.rb0000644000004100000410000000077112261240652021667 0ustar www-datawww-datadef init sections :header, [T('docstring')] end def format_args(object) return if object.parameters.nil? params = object.parameters if object.has_tag?(:yield) || object.has_tag?(:yieldparam) params.reject! do |param| param[0].to_s[0,1] == "&" && !object.tags(:param).any? {|t| t.name == param[0][1..-1] } end end unless params.empty? args = params.map {|n, v| v ? "#{h n} = #{h v}" : "" + n.to_s + "" }.join(", ") args else "" end end yard-0.8.7.3/templates/guide/method/html/header.erb0000644000004100000410000000243312261240652022121 0ustar www-datawww-data
            <% if options.in_module %> <% if object.constructor? %> self.new(<%= format_args(object) %>) <%= format_block(object) %> <% else %> <%= object.scope == :class ? 'self.' : '' %><%= object.is_attribute? ? object.name.to_s.sub(/=$/, '') : object.name %><% if object.is_attribute? %> <% rw = object.attr_info %> <% if rw && rw[:read] && !rw[:write] %>readonly <% elsif rw && !rw[:read] && rw[:write] %>writeonly <% end %> <% else %>(<%= format_args(object) %>) <%= format_block(object) %><% end %> <% end %> <% else %> def <%= options.including_object.relative_path(object.namespace) %><%= object.send(:sep) %><%= object.name %>(<%= format_args(object) %>) <%= format_block(object) %> <% end %> <% if object.has_tag?(:since) && object.namespace.tag(:since) != object.tag(:since) %>since <%= object.tag(:since).text %><% end %>
            <%= yieldall %>
            yard-0.8.7.3/templates/guide/fulldoc/0000755000004100000410000000000012261240652017401 5ustar www-datawww-datayard-0.8.7.3/templates/guide/fulldoc/html/0000755000004100000410000000000012261240652020345 5ustar www-datawww-datayard-0.8.7.3/templates/guide/fulldoc/html/js/0000755000004100000410000000000012261240652020761 5ustar www-datawww-datayard-0.8.7.3/templates/guide/fulldoc/html/js/app.js0000644000004100000410000000211612261240652022077 0ustar www-datawww-datafunction generateTOC() { if ($('#filecontents').length == 0) return; var _toc = $('
              '); var show = false; var toc = _toc; var counter = 0; var tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']; for (i in tags) { tags[i] = '#filecontents > ' + tags[i] } var lastTag = parseInt(tags[0][1]); $(tags.join(', ')).each(function() { if (this.id == "filecontents") return; show = true; var thisTag = parseInt(this.tagName[1]); if (this.id.length == 0) { var proposedId = $(this).text().replace(/[^a-z0-9-]/ig, '_'); if ($('#' + proposedId).length > 0) proposedId += counter++; this.id = proposedId; } if (thisTag > lastTag) { for (var i = 0; i < thisTag - lastTag; i++) { var tmp = $('
                '); toc.append(tmp); toc = tmp; } } if (thisTag < lastTag) { for (var i = 0; i < lastTag - thisTag; i++) toc = toc.parent(); } toc.append('
              1. ' + $(this).text() + '
              2. '); lastTag = thisTag; }); if (!show) return; $('#toc').append() $('#toc').append(_toc); } yard-0.8.7.3/templates/guide/fulldoc/html/css/0000755000004100000410000000000012261240652021135 5ustar www-datawww-datayard-0.8.7.3/templates/guide/fulldoc/html/css/style.css0000644000004100000410000001223112261240652023006 0ustar www-datawww-databody { color: #3e4349; font-family: Georgia, serif; font-size: 17px; margin: 0; } h1, h2, h3, h4, h5, h6 { font-weight: normal; color: #000; font-family: Georgia, serif; } h1 { color: #040; } h2 { color: #060; } h3 { color: #070; } h4 { color: #080; } h5 { color: #090; } #sidebar h2 { color: #2f2; } strong { color: #000; } .object_link, tt, code { font-family: 'Consolas', 'BitStream Vera Sans Mono', monospace; font-size: 14px; } .method_header .path, .module_header .path { font-family: 'Consolas', 'BitStream Vera Sans Mono', monospace; } .method_header .path.space, .module_header .path.space { padding-left: 5px; } .method_header { font-size: 0.95em; } .method_body { margin-left: 2em; } .tags h3, .tags h4 { font-size: 0.9em; font-weight: bold; color: #3e4349; } .tags .param .name { font-style: italic; } .tags .option .name { font-family: monospace; color: #000; font-size: 0.8em; } .tags .option .type, .tags .param .type { font-size: 10px; vertical-align: super; } .tags .option .type tt, .tags .param .type tt, .tags .option .type tt .object_link, .tags .param .type tt .object_link { font-size: 10px; } .module_methods { margin-left: 2em; } .method_header .since, .module_header .since { font-size: 0.75em; color: #888; vertical-align: super; } ul { list-style: square; } .inline { display: inline; } .inline p:first-child { display: inline; } .inline p { font-family: Georgia, serif; font-size: 16px; color: #3e4349; } #filecontents table, .docstring table { border-collapse: collapse; } #filecontents table th, #filecontents table td, .docstring table th, .docstring table td { border: 1px solid #ccc; padding: 8px; padding-right: 17px; } #filecontents table tr:nth-child(odd), .docstring table tr:nth-child(odd) { background: #eee; } #filecontents table tr:nth-child(even), .docstring table tr:nth-child(even) { background: #fff; } #filecontents table th, .docstring table th { background: #fff; } .docstring .note { margin: 1em 0; } .docstring h1, .docstring h2, .docstring h3, .docstring h4 { padding: 0; border: 0; border-bottom: 1px dotted #bbb; } .docstring h1 { font-size: 1.2em; } .docstring h2 { font-size: 1.1em; } .docstring h3 { font-size: 1.1em; } .docstring h4 { font-size: 1.0em; font-weight: bold; } .docstring h5 { font-size: 1.0em; font-weight: bold; } .docstring h6 { font-size: 1.0em; font-weight: bold; } #filecontents strong { font-weight: normal; color: #000; } .readonly { font-size: 0.75em; color: #888; vertical-align: super; } .rdoc-term { padding-right: 25px; font-weight: bold; } .rdoc-list p { margin: 0; padding: 0; margin-bottom: 4px; } #page { width: 940px; margin: 0px auto; } #top_nav { background: #7d0; padding: 8px 12px; } #inner_nav { width: 940px; margin: 0px auto; } #inner_nav a { border: 0; text-decoration: none; color: #777; } #inner_nav a:hover { color: #222; } #top_nav .links { display: block; float: right; } #content { margin-left: 30px; width: 660px; float: left; } #sidebar { float: left; width: 200px; float: left; padding: 18px 10px; padding-top: 0; } #sidebar h2 { font-weight: 100; color: #3e4349; font-size: 1.45em; } #sidebar ol { padding-left: 16px; margin-left: 0; list-style: square; } #sidebar a { color: #468; text-decoration: none; } #sidebar a:hover { color: #000; background: #8e0; padding: 4px; } #sidebar ol.top { padding-left: 0; margin-left: 0; list-style: none; } #sidebar a { font-size: 0.9em; } #footer { margin: 0 auto; width: 940px; text-align: center; margin-top: 30px; padding: 20px 0; color: #888; font-size: 0.8em; border-top: 1px dotted #bbb; } #footer a { color: #444; } #links strong { font-size: 0.95em; font-weight: normal; color: #000; } a { color: #268; text-decoration: none; } a:hover { color: #6ae; } /* syntax highlighting */ .source_code { display: none; padding: 3px 8px; border-left: 8px solid #ddd; margin-top: 5px; } #filecontents pre.code, .docstring pre.code, .source_code pre { font-family: monospace; } #filecontents pre.code, .docstring pre.code { display: block; } .source_code .lines { padding-right: 12px; color: #555; text-align: right; } #filecontents pre.code, .docstring pre.code, .tags pre.example { font-size: 0.9em; padding: 7px 30px; margin: 15px -30px; margin-left: -30px; background: #eee; line-height: 1.3em; font-family: 'Consolas', 'BitStream Vera Sans Mono', monospace; } pre.code { color: #3e4349; } pre.code .info.file { color: #555; } pre.code .val { color: #036A07; } pre.code .tstring_content, pre.code .heredoc_beg, pre.code .heredoc_end, pre.code .qwords_beg, pre.code .qwords_end, pre.code .tstring, pre.code .dstring { color: #036A07; } pre.code .fid, pre.code .rubyid_new, pre.code .rubyid_to_s, pre.code .rubyid_to_sym, pre.code .rubyid_to_f, pre.code .dot + pre.code .id, pre.code .rubyid_to_i pre.code .rubyid_each { color: #0085FF; } pre.code .comment { color: #0066FF; } pre.code .const, pre.code .constant { color: #585CF6; } pre.code .symbol { color: #C5060B; } pre.code .kw, pre.code .label, pre.code .rubyid_require, pre.code .rubyid_extend, pre.code .rubyid_include { color: #0000FF; } pre.code .ivar { color: #318495; } pre.code .gvar, pre.code .rubyid_backref, pre.code .rubyid_nth_ref { color: #6D79DE; } pre.code .regexp, .dregexp { color: #036A07; } pre.code a { border-bottom: 1px dotted #bbf; } yard-0.8.7.3/templates/guide/fulldoc/html/setup.rb0000644000004100000410000000342612261240652022037 0ustar www-datawww-datainclude T('default/fulldoc/html') module OverrideFileLinks def resolve_links(text) result = '' log.enter_level(Logger::ERROR) { result = super } result end def url_for(object, *args) if CodeObjects::ExtraFileObject === object && object == options.readme 'index.html' else super end end end Template.extra_includes << OverrideFileLinks def init class << options.serializer def serialized_path(object) if CodeObjects::ExtraFileObject === object super.sub(/^file\./, '').downcase else super end end end if options.serializer return serialize_onefile if options.onefile generate_assets options.delete(:objects) options.files.each {|file| serialize_file(file) } serialize_file(options.readme) end def generate_assets %w( js/jquery.js js/app.js css/style.css css/common.css ).each do |file| asset(file, file(file, true)) end end def serialize_file(file) index = options.files.index(file) outfile = file.name.downcase + '.html' options.file = file if file.attributes[:namespace] options.object = Registry.at(file.attributes[:namespace]) end options.object ||= Registry.root if file == options.readme serialize_index(options) else serialize_index(options) if !options.readme && index == 0 Templates::Engine.with_serializer(outfile, options.serializer) do T('layout').run(options) end end options.delete(:file) end def serialize_onefile layout = Object.new.extend(T('layout')) options.css_data = layout.stylesheets.map {|sheet| file(sheet,true) }.join("\n") options.js_data = layout.javascripts.map {|script| file(script,true) }.join("") Templates::Engine.with_serializer('onefile.html', options.serializer) do T('onefile').run(options) end end yard-0.8.7.3/spec/0000755000004100000410000000000012261240652013610 5ustar www-datawww-datayard-0.8.7.3/spec/server_spec.rb0000644000004100000410000000045412261240652016460 0ustar www-datawww-datarequire File.dirname(__FILE__) + "/spec_helper" describe YARD::Server do describe '.register_static_path' do it "should register a static path" do YARD::Server.register_static_path 'foo' YARD::Server::Commands::StaticFileCommand::STATIC_PATHS.last.should == "foo" end end endyard-0.8.7.3/spec/tags/0000755000004100000410000000000012261240652014546 5ustar www-datawww-datayard-0.8.7.3/spec/tags/default_factory_spec.rb0000644000004100000410000001267212261240652021270 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::Tags::DefaultFactory do before { @f = YARD::Tags::DefaultFactory.new } describe '#parse_tag' do it "should not have trailing whitespace on a regular freeform tag" do @f.parse_tag('api', 'private ').text.should == "private" end end describe '#extract_types_and_name_from_text' do def parse_types(types) @f.send(:extract_types_and_name_from_text, types) end it "should handle one type" do parse_types('[A]').should == [nil, ['A'], ""] end it "should handle a list of types" do parse_types('[A, B, C]').should == [nil, ['A', 'B', 'C'], ""] end it "should handle ducktypes" do parse_types('[#foo]').should == [nil, ['#foo'], ''] end %w(#foo= #<< #<=> #>> #== #=== Array<#<=>> Array<#==>).each do |meth| it "should handle ducktypes with special method name #{meth}" do parse_types("[#{meth}]").should == [nil, [meth], ''] end end it "should only parse #ducktypes inside brackets" do parse_types("#ducktype").should == [nil, nil, '#ducktype'] end it "should return the text before and after the type list" do parse_types(' b description').should == ['b', ['String'], 'description'] parse_types('b c description (test)').should == [nil, nil, 'b c description (test)'] end it "should handle a complex list of types" do v = parse_types(' [Test, Array, String]') v.should include(["Test", "Array", "String"]) end it "should handle any of the following start/end delimiting chars: (), <>, {}, []" do a = parse_types('[a,b,c]') b = parse_types('') c = parse_types('(a,b,c)') d = parse_types('{a,b,c}') a.should == b b.should == c c.should == d a.should include(['a','b','c']) end it "should return the text before the type list as the last element" do parse_types('b[x, y, z]').should == ['b', ['x', 'y', 'z'], ''] parse_types(' ! ').should == ["!", ['x'], ''] end it "should return text unparsed if there is no type list" do parse_types('').should == [nil, nil, ''] parse_types('[]').should == [nil, nil, '[]'] end it "should allow A => B syntax" do v = parse_types(' [Test, Array {B => C}}, C>, String]') v.should include(["Test", "Array {B => C}}, C>", "String"]) end end describe '#parse_tag_with_types' do def parse_types(text) @f.send(:parse_tag_with_types, 'test', text) end it "should parse given types and description" do YARD::Tags::Tag.should_receive(:new).with("test", "description", ["x", "y", "z"]) parse_types(' [x, y, z] description') end it "should parse given types only" do YARD::Tags::Tag.should_receive(:new).with("test", "", ["x", "y", "z"]) parse_types(' [x, y, z] ') end it "should allow type list to be omitted" do YARD::Tags::Tag.should_receive(:new).with('test', 'description', nil) parse_types(' description ') end it "should raise an error if a name is specified before type list" do lambda { parse_types('b desc') }.should raise_error(YARD::Tags::TagFormatError, 'cannot specify a name before type list for \'@test\'') end end describe '#parse_tag_with_types_name_and_default' do def parse_types(text) @f.send(:parse_tag_with_types_name_and_default, 'test', text) end it "should parse a standard type list with name before types (no default)" do YARD::Tags::DefaultTag.should_receive(:new).with("test", "description", ["x", "y", "z"], 'NAME', nil) parse_types('NAME [x, y, z] description') end it "should parse a standard type list with name after types (no default)" do YARD::Tags::DefaultTag.should_receive(:new).with("test", "description", ["x", "y", "z"], 'NAME', nil) parse_types(' [x, y, z] NAME description') end it "should parse a tag definition with name, typelist and default" do YARD::Tags::DefaultTag.should_receive(:new).with("test", "description", ["x", "y", "z"], 'NAME', ['default', 'values']) parse_types(' [x, y, z] NAME (default, values) description') end it "should parse a tag definition with name, typelist and default when name is before type list" do YARD::Tags::DefaultTag.should_receive(:new).with("test", "description", ["x", "y", "z"], 'NAME', ['default', 'values']) parse_types(' NAME [x, y, z] (default, values) description') end it "should allow typelist to be omitted" do YARD::Tags::DefaultTag.should_receive(:new).with("test", "description", nil, 'NAME', ['default', 'values']) parse_types(' NAME (default, values) description') end end describe '#parse_tag_with_options' do def parse_options(text) @f.parse_tag_with_options('option', text) end it "should have a name before tag info" do t = parse_options("xyz key [Types] (default) description") t.tag_name.should == 'option' t.name.should == 'xyz' end it "should parse the rest of the tag like DefaultTag" do t = parse_options("xyz key [Types] (default) description") t.pair.should be_instance_of(Tags::DefaultTag) t.pair.types.should == ["Types"] t.pair.name.should == "key" t.pair.defaults.should == ["default"] t.pair.text.should == "description" end end endyard-0.8.7.3/spec/tags/library_spec.rb0000644000004100000410000000214112261240652017547 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::Tags::Library do def tag(docstring) Docstring.new(docstring).tags.first end describe '#see_tag' do it "should take a URL" do tag("@see http://example.com").name.should == "http://example.com" end it "should take an object path" do tag("@see String#reverse").name.should == "String#reverse" end it "should take a description after the url/object" do tag = tag("@see http://example.com An Example Site") tag.name.should == "http://example.com" tag.text.should == "An Example Site" end end describe '.define_tag' do it "should allow defining tags with '.' in the name (x.y.z defines method x_y_z)" do Tags::Library.define_tag("foo", 'x.y.z') Tags::Library.define_tag("foo2", 'x.y.zz', Tags::OverloadTag) Tags::Library.instance.method(:x_y_z_tag).should_not be_nil Tags::Library.instance.method(:x_y_zz_tag).should_not be_nil tag('@x.y.z foo bar').text.should == 'foo bar' tag('@x.y.zz foo(bar)').signature.should == 'foo(bar)' end end end yard-0.8.7.3/spec/tags/default_tag_spec.rb0000644000004100000410000000055012261240652020364 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::Tags::DefaultTag do it "should create a tag with defaults" do o = YARD::Tags::DefaultTag.new('tagname', 'desc', ['types'], 'name', ['defaults']) o.defaults.should == ['defaults'] o.tag_name.should == 'tagname' o.name.should == 'name' o.types.should == ['types'] end endyard-0.8.7.3/spec/tags/overload_tag_spec.rb0000644000004100000410000000316512261240652020560 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::Tags::OverloadTag do before do @tag = Tags::OverloadTag.new(:overload, <<-'eof') def bar(a, b = 1, &block) Hello world @param a [String] @return [String] eof end it "should parse the first line as a method signature" do @tag.signature.should == "def bar(a, b = 1, &block)" @tag.parameters.should == [['a', nil], ['b', "1"], ['&block', nil]] end it "should parse the rest of the text as a new Docstring" do @tag.docstring.should be_instance_of(Docstring) @tag.docstring.should == "Hello world" end it "should set Docstring's object after #object= is called" do m = mock(:object) @tag.object = m @tag.docstring.object.should == m end it "should respond to #tag, #tags and #has_tag?" do @tag.object = mock(:object) @tag.tags.size.should == 2 @tag.tag(:param).name.should == "a" @tag.has_tag?(:return).should == true end it "should not be a CodeObjects::Base when not hooked up to an object" do @tag.object = nil @tag.is_a?(CodeObjects::Base).should == false end it "should be a CodeObjects::Base when hooked up to an object" do @tag.object = mock(:object) @tag.object.should_receive(:is_a?).at_least(3).times.with(CodeObjects::Base).and_return(true) @tag.is_a?(CodeObjects::Base).should == true @tag.kind_of?(CodeObjects::Base).should == true (CodeObjects::Base === @tag).should == true end it "should not parse 'def' out of method name" do tag = Tags::OverloadTag.new(:overload, "default") tag.signature.should == "default" end endyard-0.8.7.3/spec/tags/directives_spec.rb0000644000004100000410000003230312261240652020247 0ustar www-datawww-datarequire File.dirname(__FILE__) + "/../spec_helper" def tag_parse(content, object = nil, handler = nil) @parser = DocstringParser.new @parser.parse(content, object, handler) @parser end describe YARD::Tags::ParseDirective do describe '#call' do after { Registry.clear } it "should parse if handler=nil but use file=(stdin)" do tag_parse %{@!parse # Docstring here def foo; end } Registry.at('#foo').docstring.should == "Docstring here" Registry.at('#foo').file.should == '(stdin)' end it "should allow parser type to be specified in type" do tag_parse %{@!parse [c] void Init_Foo() { rb_define_method(rb_cMyClass, "foo", foo, 1); } } Registry.at('MyClass#foo').should_not be_nil end it "should parse code in context of current handler" do src = <<-eof class A # @!parse # def foo; end eval "def foo; end" end eof parser = Parser::SourceParser.new parser.file = "myfile.rb" parser.parse(StringIO.new(src)) Registry.at('A#foo').file.should == 'myfile.rb' end end end describe YARD::Tags::GroupDirective do describe '#call' do it "should do nothing if handler=nil" do tag_parse("@!group foo") end it "should set group value in parser state (with handler)" do handler = OpenStruct.new(:extra_state => OpenStruct.new) tag_parse("@!group foo", nil, handler) handler.extra_state.group.should == 'foo' end end end describe YARD::Tags::EndGroupDirective do describe '#call' do it "should do nothing if handler=nil" do tag_parse("@!endgroup foo") end it "should set group value in parser state (with handler)" do handler = OpenStruct.new(:extra_state => OpenStruct.new(:group => "foo")) tag_parse("@!endgroup", nil, handler) handler.extra_state.group.should be_nil end end end describe YARD::Tags::MacroDirective do def handler OpenStruct.new(:call_params => %w(a b c), :caller_method => 'foo', :scope => :instance, :visibility => :public, :namespace => P('Foo::Bar'), :statement => OpenStruct.new(:source => 'foo :a, :b, :c')) end after(:all) { Registry.clear } describe '#call' do it "should define new macro when [new] is provided" do tag_parse("@!macro [new] foo\n foo") CodeObjects::MacroObject.find('foo').macro_data.should == 'foo' end it "should define new macro if text block is provided" do tag_parse("@!macro bar\n bar") CodeObjects::MacroObject.find('bar').macro_data.should == 'bar' end it "should expand macros and return #expanded_text to tag parser" do tag_parse("@!macro [new] foo\n foo") tag_parse("@!macro foo").text.should == 'foo' end it "should not expand new macro if docstring is unattached" do tag_parse("@!macro [new] foo\n foo").text.should_not == 'foo' end it "should expand new anonymous macro even if docstring is unattached" do tag_parse("@!macro\n foo").text.should == 'foo' end it "should allow multiple macros to be expanded" do tag_parse("@!macro [new] foo\n foo") tag_parse("@!macro bar\n bar") tag_parse("@!macro foo\n@!macro bar").text.should == "foo\nbar" end it "should allow anonymous macros" do tag_parse("@!macro\n a b c", nil, handler) @parser.text.should == 'a b c' end it "should expand call_params and caller_method using $N when handler is provided" do tag_parse("@!macro\n $1 $2 $3", nil, handler) @parser.text.should == 'a b c' end it "should attach macro to method if one exists" do tag_parse("@!macro [attach] attached\n $1 $2 $3", nil, handler) macro = CodeObjects::MacroObject.find('attached') macro.method_object.should == P('Foo::Bar.foo') end it "should not expand new attached macro if defined on class method" do baz = CodeObjects::MethodObject.new(P('Foo::Bar'), :baz, :class) baz.visibility.should == :public tag_parse("@!macro [attach] attached2\n @!visibility private", baz, handler) macro = CodeObjects::MacroObject.find('attached2') macro.method_object.should == P('Foo::Bar.baz') baz.visibility.should == :public end it "should expand macro if defined on class method and there is no data block" do tag_parse("@!macro [new] attached3\n expanded_data") baz = CodeObjects::MethodObject.new(P('Foo::Bar'), :baz, :class) doc = DocstringParser.new.parse('@!macro attached3', baz, handler).to_docstring doc.should == 'expanded_data' end it "should not attempt to expand macro values if handler = nil" do tag_parse("@!macro [attach] xyz\n $1 $2 $3") end end end describe YARD::Tags::MethodDirective do describe '#call' do after { Registry.clear } it "should use entire docstring if no indented data is found" do YARD.parse_string <<-eof class Foo # @!method foo # @!method bar # @!scope class end eof Registry.at('Foo.foo').should be_a(CodeObjects::MethodObject) Registry.at('Foo.bar').should be_a(CodeObjects::MethodObject) end it "should handle indented block text in @!method" do YARD.parse_string <<-eof # @!method foo(a) # Docstring here # @return [String] the foo # Ignore this # @param [String] a eof foo = Registry.at('#foo') foo.docstring.should == "Docstring here" foo.docstring.tag(:return).should_not be_nil foo.tag(:param).should be_nil end it "should execute directives on object in indented block" do YARD.parse_string <<-eof class Foo # @!method foo(a) # @!scope class # @!visibility private # @!method bar # Hello # Ignore this end eof foo = Registry.at('Foo.foo') foo.visibility.should == :private bar = Registry.at('Foo#bar') bar.visibility.should == :public end it "should be able to define multiple @methods in docstring" do YARD.parse_string <<-eof class Foo # @!method foo1 # Docstring1 # @!method foo2 # Docstring2 # @!method foo3 # @!scope class # Docstring3 end eof foo1 = Registry.at('Foo#foo1') foo2 = Registry.at('Foo#foo2') foo3 = Registry.at('Foo.foo3') foo1.docstring.should == 'Docstring1' foo2.docstring.should == 'Docstring2' foo3.docstring.should == 'Docstring3' end it "should define the method inside namespace if attached to namespace object" do YARD.parse_string <<-eof module Foo # @!method foo # Docstring1 # @!method bar # Docstring2 class Bar end end eof Registry.at('Foo::Bar#foo').docstring.should == 'Docstring1' Registry.at('Foo::Bar#bar').docstring.should == 'Docstring2' end it "should set scope to class if signature has 'self.' prefix" do YARD.parse_string <<-eof # @!method self.foo # @!method self. bar # @!method self.baz() class Foo end eof %w(foo bar baz).each do |name| Registry.at("Foo.#{name}").should be_a(CodeObjects::MethodObject) end end it "should define parameters from signature" do YARD.parse_string <<-eof # @!method foo(a, b, c = nil) eof Registry.at('#foo').parameters.should == [['a', nil], ['b', nil], ['c', 'nil']] end it "should be able to define method with module scope (module function)" do YARD.parse_string <<-eof # @!method foo # @!scope module # This is a docstring # @return [Boolean] whether this is true class Foo end eof foo_c = Registry.at('Foo.foo') foo_i = Registry.at('Foo#foo') foo_c.should_not be_nil foo_i.should_not be_nil foo_c.should be_module_function foo_c.docstring.should == foo_i.docstring foo_c.tag(:return).text.should == foo_i.tag(:return).text end end end describe YARD::Tags::AttributeDirective do describe '#call' do after { Registry.clear } it "should use entire docstring if no indented data is found" do YARD.parse_string <<-eof class Foo # @!attribute foo # @!attribute bar # @!scope class end eof Registry.at('Foo.foo').should be_reader Registry.at('Foo.bar').should be_reader end it "should handle indented block in @!attribute" do YARD.parse_string <<-eof # @!attribute foo # Docstring here # @return [String] the foo # Ignore this # @param [String] a eof foo = Registry.at('#foo') foo.is_attribute?.should == true foo.docstring.should == "Docstring here" foo.docstring.tag(:return).should_not be_nil foo.tag(:param).should be_nil end it "should be able to define multiple @attributes in docstring" do YARD.parse_string <<-eof class Foo # @!attribute [r] foo1 # Docstring1 # @!attribute [w] foo2 # Docstring2 # @!attribute foo3 # @!scope class # Docstring3 end eof foo1 = Registry.at('Foo#foo1') foo2 = Registry.at('Foo#foo2=') foo3 = Registry.at('Foo.foo3') foo4 = Registry.at('Foo.foo3=') foo1.should be_reader foo2.should be_writer foo3.should be_reader foo1.docstring.should == 'Docstring1' foo2.docstring.should == 'Docstring2' foo3.docstring.should == 'Docstring3' foo4.should be_writer foo1.attr_info[:write].should be_nil foo2.attr_info[:read].should be_nil end it "should define the attr inside namespace if attached to namespace object" do YARD.parse_string <<-eof module Foo # @!attribute [r] foo # @!attribute [r] bar class Bar end end eof Registry.at('Foo::Bar#foo').should be_reader Registry.at('Foo::Bar#bar').should be_reader end end it "should set scope to class if signature has 'self.' prefix" do YARD.parse_string <<-eof # @!attribute self.foo # @!attribute self. bar # @!attribute self.baz class Foo end eof %w(foo bar baz).each do |name| Registry.at("Foo.#{name}").should be_reader end end end describe YARD::Tags::ScopeDirective do describe '#call' do after { Registry.clear } it "should set state on tag parser if object = nil" do tag_parse("@!scope class") @parser.state.scope.should == :class end it "should set state on tag parser if object is namespace" do object = CodeObjects::ClassObject.new(:root, 'Foo') tag_parse("@!scope class", object) object[:scope].should be_nil @parser.state.scope.should == :class end it "should set scope on object if object is a method object" do object = CodeObjects::MethodObject.new(:root, 'foo') tag_parse("@!scope class", object) object.scope.should == :class end %w(class instance module).each do |type| it "should allow #{type} as value" do tag_parse("@!scope #{type}") @parser.state.scope.should == type.to_sym end end %w(invalid foo FOO CLASS INSTANCE).each do |type| it "should not allow #{type} as value" do tag_parse("@!scope #{type}") @parser.state.scope.should be_nil end end end end describe YARD::Tags::VisibilityDirective do describe '#call' do after { Registry.clear } it "should set visibility on tag parser if object = nil" do tag_parse("@!visibility private") @parser.state.visibility.should == :private end it "should set state on tag parser if object is namespace" do object = CodeObjects::ClassObject.new(:root, 'Foo') tag_parse("@!visibility protected", object) object.visibility.should == :protected @parser.state.visibility.should be_nil end it "should set visibility on object if object is a method object" do object = CodeObjects::MethodObject.new(:root, 'foo') tag_parse("@!visibility private", object) object.visibility.should == :private end %w(public private protected).each do |type| it "should allow #{type} as value" do tag_parse("@!visibility #{type}") @parser.state.visibility.should == type.to_sym end end %w(invalid foo FOO PRIVATE INSTANCE).each do |type| it "should not allow #{type} as value" do tag_parse("@!visibility #{type}") @parser.state.visibility.should be_nil end end it "updates visibility on future methods" do Registry.clear YARD.parse_string <<-eof class Foo # @!visibility private def foo; end def bar; end def baz; end end eof %w(foo bar baz).each do |name| Registry.at("Foo##{name}").visibility.should == :private end end if YARD::Parser::SourceParser.parser_type == :ruby end end yard-0.8.7.3/spec/tags/ref_tag_list_spec.rb0000644000004100000410000000325212261240652020551 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::Tags::RefTagList do before { YARD::Registry.clear } it "should accept symbol or string as owner's path and convert it into a proxy" do t = Tags::RefTagList.new('author', :String) t.owner.should == P(:String) end it "should accept proxy object as owner" do t = Tags::RefTagList.new('author', P(:String)) t.owner.should == P(:String) end it "should return tags from a proxy object" do o = CodeObjects::ClassObject.new(:root, :String) t = Tags::Tag.new(:author, 'foo') o.docstring.add_tag(t) ref = Tags::RefTagList.new('author', :String) ref.tags.should == [t] ref.tags.first.text.should == 'foo' end it "should return named tags from a proxy object" do o = CodeObjects::ClassObject.new(:root, :String) p1 = Tags::Tag.new(:param, 'bar1', nil, 'foo') p2 = Tags::Tag.new(:param, 'bar2', nil, 'foo') p3 = Tags::Tag.new(:param, 'bar3', nil, 'bar') t1 = Tags::Tag.new(:return, 'blah') o.docstring.add_tag(p1, t1, p2, p3) ref = Tags::RefTagList.new('param', :String, 'foo') ref.tags.should == [p1, p2] ref.tags.first.text.should == 'bar1' end it "all tags should respond to #owner and be a RefTag" do o = CodeObjects::ClassObject.new(:root, :String) p1 = Tags::Tag.new(:param, 'bar1', nil, 'foo') p2 = Tags::Tag.new(:param, 'bar2', nil, 'foo') p3 = Tags::Tag.new(:param, 'bar3', nil, 'bar') t1 = Tags::Tag.new(:return, 'blah') o.docstring.add_tag(p1, t1, p2, p3) ref = Tags::RefTagList.new('param', :String) ref.tags.each do |t| t.should be_kind_of(Tags::RefTag) t.owner.should == o end end endyard-0.8.7.3/spec/core_ext/0000755000004100000410000000000012261240652015420 5ustar www-datawww-datayard-0.8.7.3/spec/core_ext/insertion_spec.rb0000644000004100000410000000216212261240652020772 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe Insertion do describe '#before' do it "should place an object before another" do [1, 2].place(3).before(2).should == [1, 3, 2] [1, 2].place(3).before(1).should == [3, 1, 2] [1, [4], 2].place(3).before(2).should == [1, [4], 3, 2] end end describe '#after' do it "should place an object after another" do [1, 2].place(3).after(2).should == [1, 2, 3] end it "should no longer place an object after another and its subsections (0.6)" do [1, [2]].place(3).after(1).should == [1, 3, [2]] end it "should place an array after an object" do [1, 2, 3].place([4]).after(1).should == [1, [4], 2, 3] end end describe '#before_any' do it "should place an object before another anywhere inside list (including sublists)" do [1, 2, [3]].place(4).before_any(3).should == [1, 2, [4, 3]] end end describe '#after_any' do it "should place an object after another anywhere inside list (including sublists)" do [1, 2, [3]].place(4).after_any(3).should == [1, 2, [3, 4]] end end end yard-0.8.7.3/spec/core_ext/module_spec.rb0000644000004100000410000000063212261240652020245 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe Module do describe '#class_name' do it "should return just the name of the class/module" do YARD::CodeObjects::Base.class_name.should == "Base" end end describe '#namespace' do it "should return everything before the class name" do YARD::CodeObjects::Base.namespace_name.should == "YARD::CodeObjects" end end endyard-0.8.7.3/spec/core_ext/symbol_hash_spec.rb0000644000004100000410000000406112261240652021270 0ustar www-datawww-datarequire File.join(File.dirname(__FILE__), '..', 'spec_helper') describe SymbolHash do it "should allow access to keys as String or Symbol" do h = SymbolHash.new(false) h['test'] = true h[:test].should == true h['test'].should == true end it "should #delete by key as String or Symbol" do h = SymbolHash.new h.keys.length.should == 0 h['test'] = true h.keys.length.should == 1 h.delete(:test) h.keys.length.should == 0 h[:test] = true h.keys.length.should == 1 h.delete('test') h.keys.length.should == 0 end it "should return same #has_key? for key as String or Symbol" do h = SymbolHash.new h[:test] = 1 h.has_key?(:test).should == true h.has_key?('test').should == true end it "should symbolize value if it is a String (and only a string)" do class Substring < String; end h = SymbolHash.new h['test1'] = "hello" h['test2'] = Substring.new("hello") h['test1'].should == :hello h['test2'].should == "hello" end it "should not symbolize value if SymbolHash.new(false) is created" do h = SymbolHash.new(false) h['test'] = "hello" h[:test].should == "hello" end it "should not symbolize value if it is not a String" do h = SymbolHash.new h['test'] = [1,2,3] h['test'].should == [1,2,3] end it "should support symbolization using #update or #merge!" do h = SymbolHash.new h.update('test' => 'value') h[:test].should == :value h.merge!('test' => 'value2') h[:test].should == :value2 end it "should support symbolization non-destructively using #merge" do h = SymbolHash.new h.merge('test' => 'value')[:test].should == :value h.should == SymbolHash.new end it "should support #initializing of a hash" do h = SymbolHash[:test => 1] h[:test].should == 1 h[:somethingelse].should be_nil end it "should support reverse merge syntax" do opts = {} opts = SymbolHash[ 'default' => 1 ].update(opts) opts.keys.should == [:default] opts[:default].should == 1 end end yard-0.8.7.3/spec/core_ext/file_spec.rb0000644000004100000410000000420612261240652017700 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe File do describe ".relative_path" do it "should return the relative path between two files" do File.relative_path('a/b/c/d.html', 'a/b/d/q.html').should == '../d/q.html' end it "should return the relative path between two directories" do File.relative_path('a/b/c/d/', 'a/b/d/').should == '../d' end it "should return only the to file if from file is in the same directory as the to file" do File.relative_path('a/b/c/d', 'a/b/c/e').should == 'e' end it "should handle non-normalized paths" do File.relative_path('Hello/./I/Am/Fred', 'Hello/Fred').should == '../../Fred' File.relative_path('A//B/C', 'Q/X').should == '../../Q/X' end end describe '.cleanpath' do it "should clean double brackets" do File.cleanpath('A//B/C').should == "A/B/C" end it "should clean a path with ." do File.cleanpath('Hello/./I/.Am/Fred').should == "Hello/I/.Am/Fred" end it "should clean a path with .." do File.cleanpath('Hello/../World').should == "World" end it "should clean a path with multiple .." do File.cleanpath('A/B/C/../../D').should == "A/D" end it "should clean a path ending in .." do File.cleanpath('A/B/C/D/..').should == "A/B/C" end it "should pass the initial directory" do File.cleanpath('C/../../D').should == "../D" end it "should not remove multiple '../' at the beginning" do File.cleanpath('../../A/B').should == '../../A/B' end end describe '.open!' do it "should create the path before opening" do File.should_receive(:directory?).with('/path/to').and_return(false) FileUtils.should_receive(:mkdir_p).with('/path/to') File.should_receive(:open).with('/path/to/file', 'w') File.open!('/path/to/file', 'w') end it "should just open the file if the path exists" do File.should_receive(:directory?).with('/path/to').and_return(true) FileUtils.should_not_receive(:mkdir_p) File.should_receive(:open).with('/path/to/file', 'w') File.open!('/path/to/file', 'w') end end endyard-0.8.7.3/spec/core_ext/hash_spec.rb0000644000004100000410000000060612261240652017704 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe Hash do describe '.[]' do it "should accept an Array argument (Ruby 1.8.6 and older)" do list = [['foo', 'bar'], ['foo2', 'bar2']] Hash[list].should == {'foo' => 'bar', 'foo2' => 'bar2'} end it "should accept an array as a key" do Hash[['a', 'b'], 1].should == {['a', 'b'] => 1} end end endyard-0.8.7.3/spec/core_ext/string_spec.rb0000644000004100000410000000234612261240652020272 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' #described_in_docs String, '#camelcase' #described_in_docs String, '#underscore' describe String do describe '#shell_split' do it "should split simple non-quoted text" do "a b c".shell_split.should == %w(a b c) end it "should split double quoted text into single token" do 'a "b c d" e'.shell_split.should == ["a", "b c d", "e"] end it "should split single quoted text into single token" do "a 'b c d' e".shell_split.should == ["a", "b c d", "e"] end it "should handle escaped quotations in quotes" do "'a \\' b'".shell_split.should == ["a ' b"] end it "should handle escaped quotations outside quotes" do "\\'a 'b'".shell_split.should == %w('a b) end it "should handle escaped backslash" do "\\\\'a b c'".shell_split.should == ['\a b c'] end it "should handle any whitespace as space" do text = "foo\tbar\nbaz\r\nfoo2 bar2" text.shell_split.should == %w(foo bar baz foo2 bar2) end it "should handle complex input" do text = "hello \\\"world \"1 2\\\" 3\" a 'b \"\\\\\\'' c" text.shell_split.should == ["hello", "\"world", "1 2\" 3", "a", "b \"\\'", "c"] end end endyard-0.8.7.3/spec/core_ext/array_spec.rb0000644000004100000410000000053312261240652020076 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe Array do describe '#place' do it "should create an Insertion object" do [].place('x').should be_kind_of(Insertion) end it "should allow multiple objects to be placed" do [1, 2].place('x', 'y', 'z').before(2).should == [1, 'x', 'y', 'z', 2] end end end yard-0.8.7.3/spec/logging_spec.rb0000644000004100000410000000224412261240652016577 0ustar www-datawww-datarequire File.join(File.dirname(__FILE__), "spec_helper") describe YARD::Logger do describe '#show_backtraces' do it "should be true if debug level is on" do log.show_backtraces = true log.enter_level(Logger::DEBUG) do log.show_backtraces = false log.show_backtraces.should == true end log.show_backtraces.should == false end end describe '#backtrace' do before { log.show_backtraces = true } after { log.show_backtraces = false } it "should log backtrace in error by default" do log.should_receive(:error).with("RuntimeError: foo") log.should_receive(:error).with("Stack trace:\n\tline1\n\tline2\n") exc = RuntimeError.new("foo") exc.set_backtrace(['line1', 'line2']) log.enter_level(Logger::INFO) { log.backtrace(exc) } end it "should allow backtrace to be entered in other modes" do log.should_receive(:warn).with("RuntimeError: foo") log.should_receive(:warn).with("Stack trace:\n\tline1\n\tline2\n") exc = RuntimeError.new("foo") exc.set_backtrace(['line1', 'line2']) log.enter_level(Logger::INFO) { log.backtrace(exc, :warn) } end end end yard-0.8.7.3/spec/config_spec.rb0000644000004100000410000001751712261240652016427 0ustar www-datawww-datarequire File.join(File.dirname(__FILE__), "spec_helper") require 'yaml' describe YARD::Config do describe '.load' do before do File.should_receive(:file?).twice.with(CLI::Yardoc::DEFAULT_YARDOPTS_FILE).and_return(false) end it "should use default options if no ~/.yard/config is found" do File.should_receive(:file?).with(YARD::Config::IGNORED_PLUGINS).and_return(false) File.should_receive(:file?).with(YARD::Config::CONFIG_FILE).and_return(false) YARD::Config.load YARD::Config.options.should == YARD::Config::DEFAULT_CONFIG_OPTIONS end it "should overwrite options with data in ~/.yard/config" do File.should_receive(:file?).with(YARD::Config::CONFIG_FILE).and_return(true) File.should_receive(:file?).with(YARD::Config::IGNORED_PLUGINS).and_return(false) YAML.should_receive(:load_file).with(YARD::Config::CONFIG_FILE).and_return({'test' => true}) YARD::Config.load YARD::Config.options[:test].should be_true end it "should ignore any plugins specified in '~/.yard/ignored_plugins'" do File.should_receive(:file?).with(YARD::Config::CONFIG_FILE).and_return(false) File.should_receive(:file?).with(YARD::Config::IGNORED_PLUGINS).and_return(true) File.should_receive(:read).with(YARD::Config::IGNORED_PLUGINS).and_return('yard-plugin plugin2') YARD::Config.load YARD::Config.options[:ignored_plugins].should == ['yard-plugin', 'yard-plugin2'] YARD::Config.should_not_receive(:require).with('yard-plugin2') YARD::Config.load_plugin('yard-plugin2').should == false end it "should load safe_mode setting from --safe command line option" do File.should_receive(:file?).with(YARD::Config::IGNORED_PLUGINS).and_return(false) File.should_receive(:file?).with(YARD::Config::CONFIG_FILE).and_return(false) ARGV.replace(['--safe']) YARD::Config.load YARD::Config.options[:safe_mode].should be_true ARGV.replace(['']) end end describe '.save' do it "should save options to config file" do YARD::Config.stub!(:options).and_return(:a => 1, :b => %w(a b c)) file = mock(:file) File.should_receive(:open).with(YARD::Config::CONFIG_FILE, 'w').and_yield(file) file.should_receive(:write).with(YAML.dump(:a => 1, :b => %w(a b c))) YARD::Config.save end end describe '.load_plugin' do it "should load a plugin by 'name' as 'yard-name'" do YARD::Config.should_receive(:require).with('yard-foo') log.should_receive(:debug).with(/Loading plugin 'yard-foo'/).once YARD::Config.load_plugin('foo').should == true end it "should not load plugins like 'doc-*'" do YARD::Config.should_not_receive(:require).with('yard-doc-core') YARD::Config.load_plugin('doc-core') YARD::Config.load_plugin('yard-doc-core') end it "should load plugin by 'yard-name' as 'yard-name'" do YARD::Config.should_receive(:require).with('yard-foo') log.should_receive(:debug).with(/Loading plugin 'yard-foo'/).once YARD::Config.load_plugin('yard-foo').should == true end it "should load plugin by 'yard_name' as 'yard_name'" do YARD::Config.should_receive(:require).with('yard_foo') log.should_receive(:debug).with(/Loading plugin 'yard_foo'/).once log.show_backtraces = false YARD::Config.load_plugin('yard_foo').should == true end it "should log error if plugin is not found" do YARD::Config.should_receive(:require).with('yard-foo').and_raise(LoadError) log.should_receive(:warn).with(/Error loading plugin 'yard-foo'/).once YARD::Config.load_plugin('yard-foo').should == false end it "should sanitize plugin name (remove /'s)" do YARD::Config.should_receive(:require).with('yard-foofoo') YARD::Config.load_plugin('foo/foo').should == true end it "should ignore plugins in :ignore_plugins" do YARD::Config.stub!(:options).and_return(:ignored_plugins => ['yard-foo', 'yard-bar']) YARD::Config.load_plugin('foo').should == false YARD::Config.load_plugin('bar').should == false end end describe '.load_plugins' do it "should load gem plugins if :load_plugins is true" do YARD::Config.stub!(:options).and_return(:load_plugins => true, :ignored_plugins => [], :autoload_plugins => []) YARD::Config.stub!(:load_plugin) YARD::Config.should_receive(:require).with('rubygems') YARD::Config.load_plugins end it "should ignore gem loading if RubyGems cannot load" do YARD::Config.stub!(:options).and_return(:load_plugins => true, :ignored_plugins => [], :autoload_plugins => []) YARD::Config.should_receive(:require).with('rubygems').and_raise(LoadError) YARD::Config.load_plugins.should == false end it "should load certain plugins automatically when specified in :autoload_plugins" do File.should_receive(:file?).with(CLI::Yardoc::DEFAULT_YARDOPTS_FILE).and_return(false) YARD::Config.stub!(:options).and_return(:load_plugins => false, :ignored_plugins => [], :autoload_plugins => ['yard-plugin']) YARD::Config.should_receive(:require).with('yard-plugin').and_return(true) YARD::Config.load_plugins.should == true end it "should parse --plugin from command line arguments" do YARD::Config.should_receive(:arguments).at_least(1).times.and_return(%w(--plugin foo --plugin bar a b c)) YARD::Config.should_receive(:load_plugin).with('foo').and_return(true) YARD::Config.should_receive(:load_plugin).with('bar').and_return(true) YARD::Config.load_plugins.should == true end it "should load --plugin arguments from .yardopts" do File.should_receive(:file?).with(CLI::Yardoc::DEFAULT_YARDOPTS_FILE).twice.and_return(true) File.should_receive(:file?).with(YARD::Config::CONFIG_FILE).and_return(false) File.should_receive(:file?).with(YARD::Config::IGNORED_PLUGINS).and_return(false) File.should_receive(:read_binary).with(CLI::Yardoc::DEFAULT_YARDOPTS_FILE).twice.and_return('--plugin foo') YARD::Config.should_receive(:load_plugin).with('foo') YARD::Config.load end it "should load any gem plugins starting with 'yard_' or 'yard-'" do File.should_receive(:file?).with(CLI::Yardoc::DEFAULT_YARDOPTS_FILE).and_return(false) YARD::Config.stub!(:options).and_return(:load_plugins => true, :ignored_plugins => ['yard_plugin'], :autoload_plugins => []) plugins = { 'yard' => mock('yard'), 'yard_plugin' => mock('yard_plugin'), 'yard-plugin' => mock('yard-plugin'), 'my-yard-plugin' => mock('yard-plugin'), 'rspec' => mock('rspec'), } plugins.each do |k, v| v.should_receive(:name).at_least(1).times.and_return(k) end source_mock = mock(:source_index) source_mock.should_receive(:find_name).with('').and_return(plugins.values) Gem.should_receive(:source_index).and_return(source_mock) YARD::Config.should_receive(:load_plugin).with('yard_plugin').and_return(false) YARD::Config.should_receive(:load_plugin).with('yard-plugin').and_return(true) YARD::Config.load_plugins.should == true end it "should log an error if a gem raises an error" do YARD::Config.stub!(:options).and_return(:load_plugins => true, :ignored_plugins => [], :autoload_plugins => []) plugins = { 'yard-plugin' => mock('yard-plugin') } plugins.each do |k, v| v.should_receive(:name).at_least(1).times.and_return(k) end source_mock = mock(:source_index) source_mock.should_receive(:find_name).with('').and_return(plugins.values) Gem.should_receive(:source_index).and_return(source_mock) YARD::Config.should_receive(:load_plugin).with('yard-plugin').and_raise(Gem::LoadError) log.should_receive(:warn).with(/Error loading plugin 'yard-plugin'/) YARD::Config.load_plugins.should == false end end endyard-0.8.7.3/spec/handlers/0000755000004100000410000000000012261240652015410 5ustar www-datawww-datayard-0.8.7.3/spec/handlers/module_handler_spec.rb0000644000004100000410000000173012261240652021732 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}ModuleHandler" do before(:all) { parse_file :module_handler_001, __FILE__ } it "should parse a module block" do Registry.at(:ModName).should_not == nil Registry.at("ModName::OtherModName").should_not == nil end it "should attach docstring" do Registry.at("ModName::OtherModName").docstring.should == "Docstring" end it "should handle any formatting" do Registry.at(:StressTest).should_not == nil end it "should handle complex module names" do Registry.at("A::B").should_not == nil end it "should handle modules in the form ::ModName" do Registry.at("Kernel").should_not be_nil end it "should list mixins in proper order" do Registry.at('D').mixins.should == [P(:C), P(:B), P(:A)] end it "should create proper module when constant is in namespace" do Registry.at('Q::FOO::A').should_not be_nil end endyard-0.8.7.3/spec/handlers/examples/0000755000004100000410000000000012261240652017226 5ustar www-datawww-datayard-0.8.7.3/spec/handlers/examples/visibility_handler_001.rb.txt0000644000004100000410000000055012261240652024635 0ustar www-datawww-dataclass Testing def pub; end private def priv; end def notpriv; end def notpriv2; end def notpriv?; end protected def prot; end public def pub2; end protected :notpriv, 'notpriv2', :notpriv? private name private *argument private *(method_call) def Foo; end private :Foo private class Bar; end module Baz; end endyard-0.8.7.3/spec/handlers/examples/attribute_handler_001.rb.txt0000644000004100000410000000055012261240652024451 0ustar www-datawww-datamodule A attr_writer :x end class B class << self attr_accessor :z end attr :a, true attr :a2, false attr :a3 # Docstring attr_reader :b, :c, :d attr_writer :e attr_accessor 'f' attr_accessor :z end class C def foo; end attr_writer :foo def bar=(value); end attr_reader :bar end class D protected attr_reader :parser endyard-0.8.7.3/spec/handlers/examples/class_condition_handler_001.rb.txt0000644000004100000410000000131312261240652025617 0ustar www-datawww-dataclass A if some_condition def a; end elsif 1 == 1 def b; end else def c; end end def d; end if 50 * 2 == 101 unless false def e; end else def enot; end end def g; end unless 5 * 2 == 101 def h if 1 def hnot; end end end if defined? A def j; end else def jnot; end end if defined? RUBY_VERSION def k; end else def knot; end end if 0 def nnot; end else def n; end end if 256 def o; end else def onot; end end if true def p; end else def pnot; end end if false def qnot; end else def q; end end private if a == 1 def m; end else def mnot; end end endyard-0.8.7.3/spec/handlers/examples/exception_handler_001.rb.txt0000644000004100000410000000170512261240652024447 0ustar www-datawww-dataclass Testing # Ignore yields outside methods raise NoMethodError, "reason" # Should document this def mymethod raise ArgumentError, "Argument is missing" end # Don't document this def mymethod2 raise(a) end # Don't document this (docstring takes precedence) # @raise [A] def mymethod3 raise SomethingElse end # Only document the first one (limitation of exc handler) def mymethod4 raise(A) raise B, "Argument", somethingelse end def mymethod5 raise YARD::Parser::UndocumentableError end def mymethod6 raise YARD::Handlers.constants("test") end def mymethod7 raise MethodCall('argument') end def mymethod8 raise ExceptionClass.new('blah') end def mymethod9 obj.raise IgnoreMe obj.raise(IgnoreMe) end def mymethod10 raise ArgumentError 'Message' # actually a method call end def mymethod11 raise foo('bar') end def mymethod12 raise end endyard-0.8.7.3/spec/handlers/examples/module_handler_001.rb.txt0000644000004100000410000000050312261240652023731 0ustar www-datawww-datamodule ModName private # Docstring module OtherModName end end module StressTest; end module A; end module Q module A::B end module FOO; end end module ::Kernel def x; end end module A; end module B; end module C; end class D; include A; include B; include C; end Z = Q module Z::FOO::A; end yard-0.8.7.3/spec/handlers/examples/process_handler_001.rb.txt0000644000004100000410000000026212261240652024124 0ustar www-datawww-dataclass A < NotHandler process { hello } end class B < YARD::Handlers::Ruby::Base process { test } end class C < YARD::Handlers::Ruby::Legacy::Base process do test end end yard-0.8.7.3/spec/handlers/examples/method_handler_001.rb.txt0000644000004100000410000000354112261240652023731 0ustar www-datawww-dataclass Foo class << self def inherited; end def included; end # docstring def extended; end def method_added; end def method_removed; end def method_undefined; end end # A docstring but no return type def initialize; end def ==(other) 'hello' end def /(other) 'hi' end attr_reader :method1 def method1 def dynamic; end end def self.method2; end # Docstring def String :: hello; "" end def self.new() end def [](key = 'default') puts key end def []=(key, value) end def allowed? end def ` param; end def /(x = File.new('x', 'w'), y = 2) end def |; end; def =~ () def -@; end; end def *(o) def +@; end def ~@ end end def &(o) end def %(o) end def ^(o) end def optsmeth(x, opts = {}) end def blockmeth(x, &block) end # @param a [Fixnum] # @overload def bar(a, b = 1) # @param a [String] # @return [String] # @overload def baz(b, c) # @return [Fixnum] # @overload bang(d, e) def foo(*args); end # No return tag def boolean?; end # @return without type def boolean2?; end # @return [NotBoolean, nil] def boolean3?; end # @overload rainy? # @return whether today is the rainy day. def rainy?; end attr_writer :attr_name def attr_name; end attr_reader :attr_name2 def attr_name2=; end # @option opts :bar [String] It's bar! def auto_opts(opts) end end CONST = Foo def CONST.meth_on_const; end CONST2 = CONST def CONST2.meth2_on_const; end class D alias b a # foo bar def a; end end class E # @!macro prop # @!method $1(value) # $3 # @return [$2] def self.property(name, ret_type, docstring) end property :foo, String, "create a foo" # @!macro xyz # @!method $1 def xyz; end xyz :a end module F class A def foo; end def end end # PASS def bar; end end end yard-0.8.7.3/spec/handlers/examples/class_handler_001.rb.txt0000644000004100000410000000374712261240652023566 0ustar www-datawww-data# Docstring class A module B; end private class B::C < String; def method1; end def method2; end end class X :ruby)) end it "should start with public visibility" do @proc.visibility.should == :public end it "should start in instance scope" do @proc.scope.should == :instance end it "should start in root namespace" do @proc.namespace.should == Registry.root end it "should have a globals structure" do @proc.globals.should be_a(OpenStruct) end it 'should ignore HandlerAborted exceptions (but print debug info)' do class AbortHandlerProcessor < YARD::Handlers::Ruby::Base process { abort! } end stmt = OpenStruct.new(:line => 1, :show => 'SOURCE') @proc.stub!(:find_handlers).and_return([AbortHandlerProcessor]) log.should_receive(:debug).with(/AbortHandlerProcessor cancelled from/) log.should_receive(:debug).with("\tin file '(stdin)':1:\n\nSOURCE\n") @proc.process([stmt]) end end yard-0.8.7.3/spec/handlers/alias_handler_spec.rb0000644000004100000410000000532212261240652021537 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}AliasHandler" do before(:all) { parse_file :alias_handler_001, __FILE__ } it "should throw alias into namespace object list" do P(:A).aliases[P("A#b")].should == :a end ['c', 'd?', '[]', '[]=', '-@', '%', '*', 'cstrkey', 'cstrmeth'].each do |a| it "should handle the Ruby 'alias' keyword syntax for method ##{a}" do P('A#' + a).should be_instance_of(CodeObjects::MethodObject) P('A#' + a).is_alias?.should be_true end end it "should handle keywords as the alias name" do P('A#for').should be_instance_of(CodeObjects::MethodObject) end it "should allow ConstantNames to be specified as aliases" do P('A#ConstantName').should be_instance_of(CodeObjects::MethodObject) end it "should create a new method object for the alias" do P("A#b").should be_instance_of(CodeObjects::MethodObject) end it "should pull the method into the current class if it's from another one" do P(:B).aliases[P("B#q")].should == :x P(:B).aliases[P("B#r?")].should == :x end it "should gracefully fail to pull a method in if the original method cannot be found" do P(:B).aliases[P("B#s")].should == :to_s end it "should allow complex Ruby expressions after the alias parameters" do P(:B).aliases[P("B#t")].should == :inspect end it "should show up in #is_alias? for method" do P("B#t").is_alias?.should == true P('B#r?').is_alias?.should == true end it "should allow operators and keywords to be specified as symbols" do P('B#<<').should be_instance_of(CodeObjects::MethodObject) P('B#for').should be_instance_of(CodeObjects::MethodObject) end it "should handle keywords in alias names" do P('B#do').is_alias?.should == true P('B#x2').is_alias?.should == true P(:B).aliases[P('B#do')].should == :x P(:B).aliases[P('B#x2')].should == :do end it "should handle quoted symbols" do foo = Registry.at('A#foo') foo.should_not be_nil foo.should be_is_alias Registry.at('A').aliases[foo].should == :a end it "should prepend aliases object's docstring to comments" do Registry.at('D#a').tag(:return).types.should == ['Numeric'] Registry.at('D#b').tag(:return).types.should == ['String'] Registry.at('D#b').docstring.should == "Foo bar" end it "should raise an UndocumentableError if only one parameter is passed" do undoc_error "alias_method :q" end it "should raise an UndocumentableError if the parameter is not a Symbol or String" do undoc_error "alias_method CONST, Something" undoc_error "alias_method variable, ClassName" undoc_error "alias_method variable, other_variable" end end yard-0.8.7.3/spec/handlers/constant_handler_spec.rb0000644000004100000410000000422712261240652022302 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}ConstantHandler" do before(:all) { parse_file :constant_handler_001, __FILE__ } it "should not parse constants inside methods" do Registry.at("A::B::SOMECONSTANT").source.should == "SOMECONSTANT= \"hello\"" end it "should only parse valid constants" do Registry.at("A::B::notaconstant").should be_nil end it "should maintain newlines" do Registry.at("A::B::MYCONSTANT").value.gsub("\r", "").should == "A +\nB +\nC +\nD" end it "should turn Const = Struct.new(:sym) into class Const with attr :sym" do obj = Registry.at("MyClass") obj.should be_kind_of(CodeObjects::ClassObject) attrs = obj.attributes[:instance] [:a, :b, :c].each do |key| attrs.should have_key(key) attrs[key][:read].should_not be_nil attrs[key][:write].should_not be_nil end end it "should turn Const = Struct.new('Name', :sym) into class Const with attr :sym" do obj = Registry.at("NotMyClass") obj.should be_kind_of(CodeObjects::ClassObject) attrs = obj.attributes[:instance] [:b, :c].each do |key| attrs.should have_key(key) attrs[key][:read].should_not be_nil attrs[key][:write].should_not be_nil end Registry.at("NotMyClass2").should be_nil end it "should turn Const = Struct.new into empty struct" do obj = Registry.at("MyEmptyStruct") obj.should_not be_nil obj.attributes[:instance].should be_empty end it "should maintain docstrings on structs defined via constants" do obj = Registry.at("DocstringStruct") obj.should_not be_nil obj.docstring.should == "A crazy struct." obj.attributes[:instance].should_not be_empty a1 = Registry.at("DocstringStruct#bar") a2 = Registry.at("DocstringStruct#baz") a1.docstring.should == "An attr" a1.tag(:return).types.should == ["String"] a2.docstring.should == "Another attr" a2.tag(:return).types.should == ["Number"] end it "should raise undocumentable error in 1.9 parser for Struct.new assignment to non-const" do undoc_error "nonconst = Struct.new" end unless LEGACY_PARSER endyard-0.8.7.3/spec/handlers/visibility_handler_spec.rb0000644000004100000410000000262012261240652022633 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}VisibilityHandler" do before(:all) { parse_file :visibility_handler_001, __FILE__ } it "should be able to set visibility to public" do Registry.at("Testing#pub").visibility.should == :public Registry.at("Testing#pub2").visibility.should == :public end it "should be able to set visibility to private" do Registry.at("Testing#priv").visibility.should == :private end it "should be able to set visibility to protected" do Registry.at("Testing#prot").visibility.should == :protected end it "should support parameters and only set visibility on those methods" do Registry['Testing#notpriv'].visibility.should == :protected Registry['Testing#notpriv2'].visibility.should == :protected Registry['Testing#notpriv?'].visibility.should == :protected end it "should only accept strings and symbols" do Registry.at('Testing#name').should be_nil Registry.at('Testing#argument').should be_nil Registry.at('Testing#method_call').should be_nil end it "should handle constants passed in as symbols" do Registry.at('Testing#Foo').visibility.should == :private end it 'should not register classes with visibility' do Registry.at('Testing::Bar').visibility.should == :public Registry.at('Testing::Baz').visibility.should == :public end endyard-0.8.7.3/spec/handlers/base_spec.rb0000644000004100000410000001466512261240652017675 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' require 'ostruct' include Parser describe YARD::Handlers::Base do describe "#handles and inheritance" do before do Handlers::Base.stub!(:inherited) end it "should keep track of subclasses" do Handlers::Base.should_receive(:inherited).once class TestHandler < Handlers::Base; end end it "should raise NotImplementedError if process is called on a class with no #process" do class TestNotImplementedHandler < Handlers::Base end lambda { TestNotImplementedHandler.new(0, 0).process }.should raise_error(NotImplementedError) end it "should allow multiple handles arguments" do Handlers::Base.should_receive(:inherited).once class TestHandler1 < Handlers::Base handles :a, :b, :c end TestHandler1.handlers.should == [:a, :b, :c] end it "should allow multiple handles calls" do Handlers::Base.should_receive(:inherited).once class TestHandler2 < Handlers::Base handles :a handles :b handles :c end TestHandler2.handlers.should == [:a, :b, :c] end end describe '#abort! (and HandlerAborted)' do it 'should allow HandlerAborted to be raised' do class AbortHandler1 < Handlers::Ruby::Base process { abort! } end lambda { AbortHandler1.new(nil, nil).process }.should raise_error(HandlerAborted) end end describe 'transitive tags' do it "should add transitive tags to children" do Registry.clear YARD.parse_string <<-eof # @since 1.0 # @author Foo class A def foo; end # @since 1.1 def bar; end end eof Registry.at('A').tag(:since).text.should == "1.0" Registry.at('A#foo').tag(:since).text.should == "1.0" Registry.at('A#bar').tag(:since).text.should == "1.1" Registry.at('A#bar').tag(:author).should be_nil end end describe 'sharing global state' do it "should allow globals to share global state among handlers" do class GlobalStateHandler1 < Handlers::Ruby::Base class << self; attr_accessor :state end handles :class process { self.class.state = globals.foo; globals.foo = :bar } end class GlobalStateHandler2 < Handlers::Ruby::Base class << self; attr_accessor :state end handles :def process { self.class.state = globals.foo } end 2.times do YARD.parse_string 'class Foo; end; def foo; end' GlobalStateHandler1.state.should == nil GlobalStateHandler2.state.should == :bar end end end if HAVE_RIPPER describe '#push_state' do def process(klass) state = OpenStruct.new(:namespace => "ROOT", :scope => :instance, :owner => "ROOT") klass.new(state, nil).process end it "should push and return all old state info after block" do class PushStateHandler1 < Handlers::Base def process push_state(:namespace => "FOO", :scope => :class, :owner => "BAR") do namespace.should == "FOO" scope.should == :class owner.should == "BAR" end namespace.should == "ROOT" owner.should == "ROOT" scope.should == :instance end end process PushStateHandler1 end it "should allow owner to be pushed individually" do class PushStateHandler2 < Handlers::Base def process push_state(:owner => "BAR") do namespace.should == "ROOT" scope.should == :instance owner.should == "BAR" end owner.should == "ROOT" end end process PushStateHandler2 end it "should allow scope to be pushed individually" do class PushStateHandler3 < Handlers::Base def process push_state(:scope => :foo) do namespace.should == "ROOT" scope.should == :foo owner.should == "ROOT" end scope.should == :instance end end process PushStateHandler3 end end describe '.in_file' do def parse(filename, parser_type, src = "class A; end") parser = Parser::SourceParser.new(parser_type) parser.instance_variable_set("@file", filename) parser.parse(StringIO.new(src)) end def create_handler(stmts, parser_type) $handler_counter ||= 0 sklass = parser_type == :ruby ? "Base" : "Legacy::Base" instance_eval(<<-eof) class ::InFileHandler#{$handler_counter += 1} < Handlers::Ruby::#{sklass} handles /^class/ #{stmts} def process; MethodObject.new(:root, :FOO) end end eof end def test_handler(file, stmts, creates = true, parser_type = :ruby) Registry.clear Registry.at('#FOO').should be_nil create_handler(stmts, parser_type) parse(file, parser_type) Registry.at('#FOO').send(creates ? :should_not : :should, be_nil) Handlers::Base.subclasses.delete_if {|k,v| k.to_s =~ /^InFileHandler/ } end [:ruby, :ruby18].each do |parser_type| next if parser_type == :ruby && LEGACY_PARSER describe "Parser type = #{parser_type.inspect}" do it "should allow handler to be specific to a file" do test_handler 'file_a.rb', 'in_file "file_a.rb"', true, parser_type end it "should ignore handler if filename does not match" do test_handler 'file_b.rb', 'in_file "file_a.rb"', false, parser_type end it "should only test filename part when given a String" do test_handler '/path/to/file_a.rb', 'in_file "/to/file_a.rb"', false, parser_type end it "should test exact match for entire String" do test_handler 'file_a.rb', 'in_file "file"', false, parser_type end it "should allow a Regexp as argument and test against full path" do test_handler 'file_a.rbx', 'in_file /\.rbx$/', true, parser_type test_handler '/path/to/file_a.rbx', 'in_file /\/to\/file_/', true, parser_type test_handler '/path/to/file_a.rbx', 'in_file /^\/path/', true, parser_type end it "should allow multiple in_file declarations" do stmts = 'in_file "x"; in_file /y/; in_file "foo.rb"' test_handler 'foo.rb', stmts, true, parser_type test_handler 'xyzzy.rb', stmts, true, parser_type test_handler 'x', stmts, true, parser_type end end end end end yard-0.8.7.3/spec/handlers/legacy_base_spec.rb0000644000004100000410000001051612261240652021210 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' include Parser::Ruby::Legacy describe YARD::Handlers::Ruby::Legacy::Base, "#tokval" do before { @handler = Handlers::Ruby::Legacy::Base.new(nil, nil) } def tokval(code, *types) @handler.send(:tokval, TokenList.new(code).first, *types) end it "should return the String's value without quotes" do tokval('"hello"').should == "hello" end it "should not allow interpolated strings with TkSTRING" do tokval('"#{c}"', RubyToken::TkSTRING).should be_nil end it "should return a Symbol's value as a String (as if it was done via :name.to_sym)" do tokval(':sym').should == :sym end it "should return nil for any non accepted type" do tokval('identifier').should be_nil tokval(':sym', RubyToken::TkId).should be_nil end it "should accept TkVal tokens by default" do tokval('2.5').should == 2.5 tokval(':sym').should == :sym end it "should accept any ID type if TkId is set" do tokval('variable', RubyToken::TkId).should == "variable" tokval('CONSTANT', RubyToken::TkId).should == "CONSTANT" end it "should allow extra token types to be accepted" do tokval('2.5', RubyToken::TkFLOAT).should == 2.5 tokval('2', RubyToken::TkFLOAT).should be_nil tokval(':symbol', RubyToken::TkFLOAT).should be_nil end it "should allow :string for any string type" do tokval('"hello"', :string).should == "hello" tokval('"#{c}"', :string).should == '#{c}' end it "should not include interpolated strings when using :attr" do tokval('"#{c}"', :attr).should be_nil end it "should allow any number type with :number" do tokval('2.5', :number).should == 2.5 tokval('2', :number).should == 2 end it "should should allow method names with :identifier" do tokval('methodname?', :identifier).should == "methodname?" end #it "should obey documentation expectations" do docspec end end describe YARD::Handlers::Base, "#tokval_list" do before { @handler = Handlers::Ruby::Legacy::Base.new(nil, nil) } def tokval_list(code, *types) @handler.send(:tokval_list, TokenList.new(code), *types) end it "should return the list of tokvalues" do tokval_list(":a, :b, \"\#{c}\", 'd'", :attr).should == [:a, :b, 'd'] tokval_list(":a, :b, File.read(\"\#{c}\", ['w']), :d", RubyToken::Token).should == [:a, :b, 'File.read("#{c}", [\'w\'])', :d] end it "should try to skip any invalid tokens" do tokval_list(":a, :b, \"\#{c}\", :d", :attr).should == [:a, :b, :d] tokval_list(":a, :b, File.read(\"\#{c}\", 'w', File.open { }), :d", :attr).should == [:a, :b, :d] tokval_list("CONST1, identifier, File.read(\"\#{c}\", 'w', File.open { }), CONST2", RubyToken::TkId).should == ['CONST1', 'identifier', 'CONST2'] end it "should ignore a token if another invalid token is read before a comma" do tokval_list(":a, :b XYZ, :c", RubyToken::TkSYMBOL).should == [:a, :c] end it "should stop on most keywords" do tokval_list(':a rescue :x == 5', RubyToken::Token).should == [:a] end it "should handle ignore parentheses that begin the token list" do tokval_list('(:a, :b, :c)', :attr).should == [:a, :b, :c] end it "should end when a closing parenthesis was found" do tokval_list(':a, :b, :c), :d', :attr).should == [:a, :b, :c] end it "should ignore parentheses around items in a list" do tokval_list(':a, (:b), :c, (:d TEST), :e, [:f], :g', :attr).should == [:a, :b, :c, :e, :g] tokval_list(':a, (((:f)))', :attr).should == [:a, :f] tokval_list(':a, ([:f]), :c)', RubyToken::Token).should == [:a, '[:f]', :c] end it "should not stop on a true/false/self keyword (cannot handle nil)" do tokval_list(':a, true, :b, self, false, :c, nil, File, super, if, XYZ', RubyToken::Token).should == [:a, true, :b, 'self', false, :c, 'File', 'super'] end it "should ignore invalid commas" do tokval_list(":a, :b, , :d").should == [:a, :b, :d] end it "should return an empty list if no matches were found" do tokval_list('attr_accessor :x').should == [] end it "should treat {} as a valid value" do # FIXME: tokval_list destroys extra spaces surrounding the '=' in # this situation. This is technically a design flaw of the # tokval parser, but this is now the expected behaviour. tokval_list("opts = {}", :all).should == ["opts={}"] end endyard-0.8.7.3/spec/handlers/mixin_handler_spec.rb0000644000004100000410000000360412261240652021573 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}MixinHandler" do before(:all) { parse_file :mixin_handler_001, __FILE__ } it "should handle includes from classes or modules" do Registry.at(:X).instance_mixins.should include(P(:A)) Registry.at(:Y).instance_mixins.should include(P(:A)) end it "should handle includes in class << self" do Registry.at(:Y).class_mixins.should include(P(:A)) end it "should handle includes for modules that don't yet exist" do Registry.at(:X).instance_mixins.should include(P(nil, :NOTEXIST)) end it "should set the type of non-existing modules to :module" do o = Registry.at(:X).instance_mixins.find {|o| o.name == :NOTEXIST } o.type.should == :module end it "should handle includes with multiple parameters" do Registry.at(:X).should_not be_nil end it "should handle complex include statements" do P(:Y).instance_mixins.should include(P('B::C')) P(:Y).instance_mixins.should include(P(:B)) end it "should treat a mixed in Constant by taking its value as the real object name" do P(:Y).instance_mixins.should include(Registry.at('B::D')) end it "should add includes in the correct order when include is given multiple arguments" do P(:Z).instance_mixins.should == [P(:A), P(:B)] end it "should avoid including self for unresolved mixins of the same name" do P("ABC::DEF::FOO").mixins.should == [P("ABC::FOO")] P("ABC::DEF::BAR").mixins.should == [P("ABC::BAR")] end it "should raise undocumentable error if argument is variable" do undoc_error "module X; include invalid; end" Registry.at('X').mixins.should == [] end it "should parse all other arguments before erroring out on undocumentable error" do undoc_error "module X; include invalid, Y; end" Registry.at('X').mixins.should == [P('Y')] end end yard-0.8.7.3/spec/handlers/exception_handler_spec.rb0000644000004100000410000000316012261240652022442 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}ExceptionHandler" do before(:all) { parse_file :exception_handler_001, __FILE__ } it "should not document an exception outside of a method" do P('Testing').has_tag?(:raise).should == false end it "should document a valid raise" do P('Testing#mymethod').tag(:raise).types.should == ['ArgumentError'] end it "should only document non-dynamic raises" do P('Testing#mymethod2').tag(:raise).should be_nil P('Testing#mymethod6').tag(:raise).should be_nil P('Testing#mymethod7').tag(:raise).should be_nil end it "should treat ConstantName.new as a valid exception class" do P('Testing#mymethod8').tag(:raise).types.should == ['ExceptionClass'] end it "should not document a method with an existing @raise tag" do P('Testing#mymethod3').tag(:raise).types.should == ['A'] end it "should only document the first raise message of a method (limitation of exception handler)" do P('Testing#mymethod4').tag(:raise).types.should == ['A'] end it "should handle complex class names" do P('Testing#mymethod5').tag(:raise).types.should == ['YARD::Parser::UndocumentableError'] end it "should ignore any raise calls on a receiver" do P('Testing#mymethod9').tag(:raise).should be_nil end it "should handle raise expressions that are method calls" do P('Testing#mymethod10').tag(:raise).should be_nil P('Testing#mymethod11').tag(:raise).should be_nil end it "should ignore empty raise call" do P('Testing#mymethod12').tag(:raise).should be_nil end endyard-0.8.7.3/spec/handlers/method_handler_spec.rb0000644000004100000410000001361712261240652021734 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}MethodHandler" do before(:all) do log.enter_level(Logger::ERROR) do parse_file :method_handler_001, __FILE__ end end it "should add methods to parent's #meths list" do P(:Foo).meths.should include(P("Foo#method1")) end it "should parse/add class methods (self.method2)" do P(:Foo).meths.should include(P("Foo.method2")) end it "should parse/add class methods from other namespaces (String.hello)" do P("String.hello").should be_instance_of(CodeObjects::MethodObject) end [:[], :[]=, :allowed?, :/, :=~, :==, :`, :|, :*, :&, :%, :'^', :-@, :+@, :'~@'].each do |name| it "should allow valid method #{name}" do Registry.at("Foo##{name}").should_not be_nil end end it "should allow self.methname" do Registry.at("Foo.new").should_not be_nil end it "should mark dynamic methods as such" do P('Foo#dynamic').dynamic?.should == true end it "should show that a method is explicitly defined (if it was originally defined implicitly by attribute)" do P('Foo#method1').is_explicit?.should == true end it "should handle parameters" do P('Foo#[]').parameters.should == [['key', "'default'"]] P('Foo#/').parameters.should == [['x', "File.new('x', 'w')"], ['y', '2']] end it "should handle opts = {} as parameter" do P('Foo#optsmeth').parameters.should == [['x', nil], ['opts', '{}']] end it "should handle &block as parameter" do P('Foo#blockmeth').parameters.should == [['x', nil], ['&block', nil]] end it "should handle overloads" do meth = P('Foo#foo') o1 = meth.tags(:overload).first o1.name.should == :bar o1.parameters.should == [['a', nil], ['b', "1"]] o1.tag(:return).type.should == "String" o2 = meth.tags(:overload)[1] o2.name.should == :baz o2.parameters.should == [['b', nil], ['c', nil]] o2.tag(:return).type.should == "Fixnum" o3 = meth.tags(:overload)[2] o3.name.should == :bang o3.parameters.should == [['d', nil], ['e', nil]] o3.docstring.should be_empty o3.docstring.should be_blank end it "should set a return tag if not set on #initialize" do meth = P('Foo#initialize') meth.should have_tag(:return) meth.tag(:return).types.should == ["Foo"] meth.tag(:return).text.should == "a new instance of Foo" end %w(inherited included method_added method_removed method_undefined).each do |meth| it "should set @private tag on #{meth} callback method if no docstring is set" do P('Foo.' + meth).should have_tag(:private) end end it "should not set @private tag on extended callback method since docstring is set" do P('Foo.extended').should_not have_tag(:private) end it "should add @return [Boolean] tag to methods ending in ? without return types" do meth = P('Foo#boolean?') meth.should have_tag(:return) meth.tag(:return).types.should == ['Boolean'] end it "should add Boolean type to return tag without types" do meth = P('Foo#boolean2?') meth.should have_tag(:return) meth.tag(:return).types.should == ['Boolean'] end it "should not change return type for method ending in ? with return types set" do meth = P('Foo#boolean3?') meth.should have_tag(:return) meth.tag(:return).types.should == ['NotBoolean', 'nil'] end it "should not change return type for method ending in ? with return types set by @overload" do meth = P('Foo#rainy?') meth.should have_tag(:overload) meth.tag(:overload).should have_tag(:return) meth.should_not have_tag(:return) end it "should add method writer to existing attribute" do Registry.at('Foo#attr_name').should be_reader Registry.at('Foo#attr_name=').should be_writer end it "should add method reader to existing attribute" do Registry.at('Foo#attr_name2').should be_reader Registry.at('Foo#attr_name2=').should be_writer end it "should generate an options parameter if @option refers to an undocumented parameter" do meth = P('Foo#auto_opts') meth.should have_tag(:param) meth.tag(:param).name.should == "opts" meth.tag(:param).types.should == ["Hash"] end it "should raise an undocumentable error when a method is defined on an object instance" do undoc_error "error = Foo; def error.at(foo) end" Registry.at('error').should be_nil end it "should allow class method to be defined on constant reference object" do Registry.at('Foo.meth_on_const').should_not be_nil Registry.at('Foo.meth2_on_const').should_not be_nil end it "should copy alias information on method (re-)definition to new method" do Registry.at('D').aliases.should be_empty Registry.at('D#b').is_alias?.should == false Registry.at('D#a').is_alias?.should == false end it "should add macros for class methods" do macro = CodeObjects::MacroObject.find('prop') macro.should_not be_nil macro.macro_data.should == "@!method $1(value)\n$3\n@return [$2]" macro.method_object.should == Registry.at('E.property') macro.should be_attached obj = Registry.at('E#foo') obj.should_not be_nil obj.docstring.should == 'create a foo' obj.signature.should == 'def foo(value)' obj.tag(:return).types.should == ['String'] end it "should handle macros on any object" do macro = CodeObjects::MacroObject.find('xyz') macro.should_not be_nil macro.macro_data.should == '@!method $1' end it "should skip macros on instance methods" do Registry.at('E#a').should be_nil end it "should warn if the macro name is invalid" do log.should_receive(:warn).with(/Invalid directive.*@!macro/) YARD.parse_string "class Foo\n# @!macro\ndef self.foo; end\nend" end it "should handle 'def end' methods" do obj = Registry.at('F::A#foo') obj.should_not be_nil obj = Registry.at('F::A#bar') obj.should_not be_nil obj.docstring.should == 'PASS' end end yard-0.8.7.3/spec/handlers/class_handler_spec.rb0000644000004100000410000002120512261240652021551 0ustar www-datawww-datarequire File.expand_path(File.dirname(__FILE__) + '/spec_helper') describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}ClassHandler" do before(:all) { parse_file :class_handler_001, __FILE__ } it "should parse a class block with docstring" do P("A").docstring.should == "Docstring" end it "should handle complex class names" do P("A::B::C").should_not == nil end it "should handle the subclassing syntax" do P("A::B::C").superclass.should == P(:String) P("A::X").superclass.should == Registry.at("A::B::C") end it "should interpret class << self as a class level block" do P("A.classmethod1").should_not == nil end it "should interpret class << ClassName as a class level block in ClassName's namespace" do P("A::B::C.Hello").should be_instance_of(CodeObjects::MethodObject) end it "should make visibility public when parsing a block" do P("A::B::C#method1").visibility.should == :public end it "should set superclass type to :class if it is a Proxy" do P("A::B::C").superclass.type.should == :class end it "should look for a superclass before creating the class if it shares the same name" do P('B::A').superclass.should == P('A') end it "should handle class definitions in the form ::ClassName" do Registry.at("MyRootClass").should_not be_nil end it "should handle superclass as a constant-style method (camping style < R /path/)" do P('Test1').superclass.should == P(:R) P('Test2').superclass.should == P(:R) P('Test6').superclass.should == P(:NotDelegateClass) end it "should handle superclass with OStruct.new or Struct.new syntax (superclass should be OStruct/Struct)" do P('Test3').superclass.should == P(:Struct) P('Test4').superclass.should == P(:OStruct) end it "should handle DelegateClass(CLASSNAME) superclass syntax" do P('Test5').superclass.should == P(:Array) end it "should handle a superclass of the same name in the form ::ClassName" do P('Q::Logger').superclass.should == P(:Logger) P('Q::Foo').superclass.should_not == P('Q::Logger') end ["CallMethod('test')", "VSD^#}}", 'not.aclass', 'self'].each do |klass| it "should raise an UndocumentableError for invalid class '#{klass}'" do with_parser(:ruby18) { undoc_error "class #{klass}; end" } end end ['@@INVALID', 'hi', '$MYCLASS', 'AnotherClass.new'].each do |klass| it "should raise an UndocumentableError for invalid superclass '#{klass}' but it should create the class." do YARD::CodeObjects::ClassObject.should_receive(:new).with(Registry.root, 'A') with_parser(:ruby18) { undoc_error "class A < #{klass}; end" } Registry.at('A').superclass.should == P(:Object) end end ['not.aclass', 'self', 'AnotherClass.new'].each do |klass| it "should raise an UndocumentableError if the constant class reference 'class << SomeConstant' does not point to a valid class name" do with_parser(:ruby18) do undoc_error <<-eof CONST = #{klass} class << CONST; end eof end Registry.at(klass).should be_nil end end it "should document 'class << SomeConstant' by using SomeConstant's value as a reference to the real class name" do Registry.at('String.classmethod').should_not be_nil end it "should allow class << SomeRubyClass to create the class if it does not exist" do Registry.at('Symbol.toString').should_not be_nil end it "should document 'class Exception' without running into superclass issues" do Parser::SourceParser.parse_string <<-eof class Exception end eof Registry.at(:Exception).should_not be_nil end it "should document 'class RT < XX::RT' with proper superclass even if XX::RT is a proxy" do Registry.at(:RT).should_not be_nil Registry.at(:RT).superclass.should == P('XX::RT') end it "should not overwrite docstring with an empty one" do Registry.at(:Zebra).docstring.should == "Docstring 2" end it "should turn 'class Const < Struct.new(:sym)' into class Const with attr :sym" do obj = Registry.at("Point") obj.should be_kind_of(CodeObjects::ClassObject) attrs = obj.attributes[:instance] [:x, :y, :z].each do |key| attrs.should have_key(key) attrs[key][:read].should_not be_nil attrs[key][:write].should_not be_nil end end it "should turn 'class Const < Struct.new('Name', :sym)' into class Const with attr :sym" do obj = Registry.at("AnotherPoint") obj.should be_kind_of(CodeObjects::ClassObject) attrs = obj.attributes[:instance] [:a, :b, :c].each do |key| attrs.should have_key(key) attrs[key][:read].should_not be_nil attrs[key][:write].should_not be_nil end Registry.at("XPoint").should be_nil end it "should create a Struct::Name class when class Const < Struct.new('Name', :sym) is found" do obj = Registry.at("Struct::XPoint") obj.should_not be_nil end it "should attach attribtues to the generated Struct::Name class when Struct.new('Name') is used" do obj = Registry.at("Struct::XPoint") attrs = obj.attributes[:instance] [:a, :b, :c].each do |key| attrs.should have_key(key) attrs[key][:read].should_not be_nil attrs[key][:write].should_not be_nil end end it "should use @attr to set attribute descriptions on Struct subclasses" do obj = Registry.at("DoccedStruct#input") obj.docstring.should == "the input stream" end it "should use @attr to set attribute types on Struct subclasses" do obj = Registry.at("DoccedStruct#someproc") obj.should_not be_nil obj.tag(:return).should_not be_nil obj.tag(:return).types.should == ["Proc", "#call"] end it "should default types unspecified by @attr to Object on Struct subclasses" do obj = Registry.at("DoccedStruct#mode") obj.should_not be_nil obj.tag(:return).should_not be_nil obj.tag(:return).types.should == ["Object"] end it "should create parameters for writers of Struct subclass's attributes" do obj = Registry.at("DoccedStruct#input=") obj.tags(:param).size.should == 1 obj.tag(:param).types.should == ["IO"] end ["SemiDoccedStruct", "NotAStruct"].each do |struct| describe("Attributes on a " + (struct == "NotAStruct" ? "class" : "struct")) do it "defines both readers and writers when @attr is used on Structs" do obj = Registry.at(struct) attrs = obj.attributes[:instance] attrs[:first][:read].should_not be_nil attrs[:first][:write].should_not be_nil end it "defines only a reader when only @attr_reader is used on Structs" do obj = Registry.at(struct) attrs = obj.attributes[:instance] attrs[:second][:read].should_not be_nil attrs[:second][:write].should be_nil end it "defines only a writer when only @attr_writer is used on Structs" do obj = Registry.at(struct) attrs = obj.attributes[:instance] attrs[:third][:read].should be_nil attrs[:third][:write].should_not be_nil end it "defines a reader with correct return types when @attr_reader is used on Structs" do obj = Registry.at("#{struct}#second") obj.tag(:return).types.should == ["Fixnum"] end it "defines a writer with correct parameter types when @attr_writer is used on Structs" do obj = Registry.at("#{struct}#third=") obj.tag(:param).types.should == ["Array"] end it "defines a reader and a writer when both @attr_reader and @attr_writer are used" do obj = Registry.at(struct) attrs = obj.attributes[:instance] attrs[:fourth][:read].should_not be_nil attrs[:fourth][:write].should_not be_nil end it "uses @attr_reader for the getter when both @attr_reader and @attr_writer are given" do obj = Registry.at("#{struct}#fourth") obj.tag(:return).types.should == ["#read"] end it "uses @attr_writer for the setter when both @attr_reader and @attr_writer are given" do obj = Registry.at("#{struct}#fourth=") obj.tag(:param).types.should == ["IO"] end it "extracts text from @attr_reader" do Registry.at("#{struct}#fourth").docstring.should == "returns a proc that reads" end it "extracts text from @attr_writer" do Registry.at("#{struct}#fourth=").docstring.should == "sets the proc that writes stuff" end end end it "should inherit from a regular struct" do Registry.at('RegularStruct').superclass.should == P(:Struct) Registry.at('RegularStruct2').superclass.should == P(:Struct) end it "should handle inheritance from 'self'" do Registry.at('Outer1::Inner1').superclass.should == Registry.at('Outer1') end endyard-0.8.7.3/spec/handlers/attribute_handler_spec.rb0000644000004100000410000000556212261240652022457 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}AttributeHandler" do before(:all) { parse_file :attribute_handler_001, __FILE__ } def read_write(namespace, name, read, write, scope = :instance) rname, wname = namespace.to_s+"#"+name.to_s, namespace.to_s+"#"+name.to_s+"=" if read Registry.at(rname).should be_instance_of(CodeObjects::MethodObject) else Registry.at(rname).should == nil end if write Registry.at(wname).should be_kind_of(CodeObjects::MethodObject) else Registry.at(wname).should == nil end attrs = Registry.at(namespace).attributes[scope][name] attrs[:read].should == (read ? Registry.at(rname) : nil) attrs[:write].should == (write ? Registry.at(wname) : nil) end it "should parse attributes inside modules too" do Registry.at("A#x=").should_not == nil end it "should parse 'attr'" do read_write(:B, :a, true, true) read_write(:B, :a2, true, false) read_write(:B, "a3", true, false) end it "should parse 'attr_reader'" do read_write(:B, :b, true, false) end it "should parse 'attr_writer'" do read_write(:B, :e, false, true) end it "should parse 'attr_accessor'" do read_write(:B, :f, true, true) end it "should parse a list of attributes" do read_write(:B, :b, true, false) read_write(:B, :c, true, false) read_write(:B, :d, true, false) end it "should have a default docstring if one is not supplied" do Registry.at("B#f=").docstring.should_not be_empty end it "should set the correct docstring if one is supplied" do Registry.at("B#b").docstring.should == "Docstring" Registry.at("B#c").docstring.should == "Docstring" Registry.at("B#d").docstring.should == "Docstring" end it "should be able to differentiate between class and instance attributes" do P('B').class_attributes[:z][:read].scope.should == :class P('B').instance_attributes[:z][:read].scope.should == :instance end it "should respond true in method's #is_attribute?" do P('B#a').is_attribute?.should == true P('B#a=').is_attribute?.should == true end it "should not return true for #is_explicit? in created methods" do Registry.at(:B).meths.each do |meth| meth.is_explicit?.should == false end end it "should handle attr call with no arguments" do lambda { StubbedSourceParser.parse_string "attr" }.should_not raise_error end it "should add existing reader method as part of attr_writer combo" do Registry.at('C#foo=').attr_info[:read].should == Registry.at('C#foo') end it "should add existing writer method as part of attr_reader combo" do Registry.at('C#foo').attr_info[:write].should == Registry.at('C#foo=') end it "should maintain visibility for attr_reader" do Registry.at('D#parser').visibility.should == :protected end endyard-0.8.7.3/spec/handlers/ruby/0000755000004100000410000000000012261240652016371 5ustar www-datawww-datayard-0.8.7.3/spec/handlers/ruby/legacy/0000755000004100000410000000000012261240652017635 5ustar www-datawww-datayard-0.8.7.3/spec/handlers/ruby/legacy/base_spec.rb0000644000004100000410000000507412261240652022114 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../../spec_helper' include Parser::Ruby::Legacy describe YARD::Handlers::Ruby::Legacy::Base, "#handles and inheritance" do before do Handlers::Ruby::Legacy::Base.stub!(:inherited) Handlers::Ruby::Legacy::MixinHandler.stub!(:inherited) # fixes a Ruby1.9 issue @processor = Handlers::Processor.new(OpenStruct.new(:parser_type => :ruby18)) end after(:all) do Handlers::Base.clear_subclasses end def stmt(string) Statement.new(TokenList.new(string)) end it "should only handle Handlers inherited from Ruby::Legacy::Base class" do class IgnoredHandler < Handlers::Base handles "hello" end class NotIgnoredHandlerLegacy < Handlers::Ruby::Legacy::Base handles "hello" end Handlers::Base.stub!(:subclasses).and_return [IgnoredHandler, NotIgnoredHandlerLegacy] @processor.find_handlers(stmt("hello world")).should == [NotIgnoredHandlerLegacy] end it "should handle a string input" do class TestStringHandler < Handlers::Ruby::Legacy::Base handles "hello" end TestStringHandler.handles?(stmt("hello world")).should be_true TestStringHandler.handles?(stmt("nothello world")).should be_false end it "should handle regex input" do class TestRegexHandler < Handlers::Ruby::Legacy::Base handles /^nothello$/ end TestRegexHandler.handles?(stmt("nothello")).should be_true TestRegexHandler.handles?(stmt("not hello hello")).should be_false end it "should handle token input" do class TestTokenHandler < Handlers::Ruby::Legacy::Base handles TkMODULE end TestTokenHandler.handles?(stmt("module")).should be_true TestTokenHandler.handles?(stmt("if")).should be_false end it "should parse a do/end or { } block with #parse_block" do class MyBlockHandler < Handlers::Ruby::Legacy::Base handles /\AmyMethod\b/ def process parse_block(:owner => "test") end end class MyBlockInnerHandler < Handlers::Ruby::Legacy::Base handles "inner" def self.reset; @@reached = false end def self.reached?; @@reached ||= false end def process; @@reached = true end end Handlers::Base.stub!(:subclasses).and_return [MyBlockHandler, MyBlockInnerHandler] Parser::SourceParser.parser_type = :ruby18 Parser::SourceParser.parse_string "myMethod do inner end" MyBlockInnerHandler.should be_reached MyBlockInnerHandler.reset Parser::SourceParser.parse_string "myMethod { inner }" MyBlockInnerHandler.should be_reached Parser::SourceParser.parser_type = :ruby end end yard-0.8.7.3/spec/handlers/ruby/base_spec.rb0000644000004100000410000000576112261240652020653 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::Handlers::Ruby::Base, '#valid_handler?' do include YARD::Parser::Ruby; YARD::Parser::Ruby::AstNode before do Handlers::Ruby::Base.stub!(:inherited) @processor = Handlers::Processor.new(OpenStruct.new(:parser_type => :ruby)) end after(:all) do Handlers::Base.clear_subclasses end def valid(handler, stmt) @processor.find_handlers(stmt).should include(handler) end def invalid(handler, stmt) @processor.find_handlers(stmt).should_not include(handler) end it "should only handle Handlers inherited from Ruby::Base class" do class IgnoredHandler < Handlers::Base handles :list end class NotIgnoredHandler < Handlers::Ruby::Base handles :list end Handlers::Base.stub!(:subclasses).and_return [IgnoredHandler, NotIgnoredHandler] @processor.find_handlers(s()).should == [NotIgnoredHandler] end it "should handle string input (matches AstNode#source)" do class StringHandler < Handlers::Ruby::Base handles "x" end Handlers::Base.stub!(:subclasses).and_return [StringHandler] ast = Parser::Ruby::RubyParser.parse("if x == 2 then true end").ast valid StringHandler, ast[0][0][0] invalid StringHandler, ast[0][1] end it "should handle symbol input (matches AstNode#type)" do class SymbolHandler < Handlers::Ruby::Base handles :myNodeType end Handlers::Base.stub!(:subclasses).and_return [SymbolHandler] valid SymbolHandler, s(:myNodeType, s(1, 2, 3)) invalid SymbolHandler, s(:NOTmyNodeType, s(1, 2, 3)) end it "should handle regex input (matches AstNode#source)" do class RegexHandler < Handlers::Ruby::Base handles %r{^if x ==} end Handlers::Base.stub!(:subclasses).and_return [RegexHandler] ast = Parser::Ruby::RubyParser.parse("if x == 2 then true end").ast valid RegexHandler, ast invalid RegexHandler, ast[0][1] end it "should handle AstNode input (matches AST literally)" do class ASTHandler < Handlers::Ruby::Base handles s(:vcall, s(:ident, "hello_world")) end Handlers::Base.stub!(:subclasses).and_return [ASTHandler] valid ASTHandler, s(:vcall, s(:ident, "hello_world")) invalid ASTHandler, s(:vcall, s(:ident, "NOTHELLOWORLD")) end it "should handle #method_call(:methname) on a valid AST" do class MethCallHandler < Handlers::Ruby::Base handles method_call(:meth) end Handlers::Base.stub!(:subclasses).and_return [MethCallHandler] ast = Parser::Ruby::RubyParser.parse(<<-"eof").ast meth # 0 meth() # 1 meth(1,2,3) # 2 meth 1,2,3 # 3 NotMeth.meth # 4 NotMeth.meth { } # 5 NotMeth.meth do end # 6 NotMeth.meth 1, 2, 3 # 7 NotMeth.meth(1, 2, 3) # 8 NotMeth # 9 eof (0..8).each do |i| valid MethCallHandler, ast[i] end invalid MethCallHandler, ast[9] end end if HAVE_RIPPER yard-0.8.7.3/spec/handlers/yield_handler_spec.rb0000644000004100000410000000415512261240652021557 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}YieldHandler" do before(:all) { parse_file :yield_handler_001, __FILE__ } it "should only parse yield blocks in methods" do P(:Testing).tag(:yield).should be_nil P(:Testing).tag(:yieldparam).should be_nil end it "should handle an empty yield statement" do P('Testing#mymethod').tag(:yield).should be_nil P('Testing#mymethod').tag(:yieldparam).should be_nil end it "should not document a yield statement in a method with either @yield or @yieldparam" do P('Testing#mymethod2').tag(:yield).types.should == ['a', 'b'] P('Testing#mymethod2').tag(:yield).text.should == "Blah" P('Testing#mymethod2').tags(:yieldparam).size.should == 2 P('Testing#mymethod3').tag(:yield).types.should == ['a', 'b'] P('Testing#mymethod3').tags(:yieldparam).size.should == 0 P('Testing#mymethod4').tag(:yieldparam).name.should == '_self' P('Testing#mymethod4').tag(:yieldparam).text.should == 'BLAH' end it "should handle any arbitrary yield statement" do P('Testing#mymethod5').tag(:yield).types.should == [':a', 'b', '_self', 'File.read(\'file\', \'w\')', 'CONSTANT'] end it "should handle parentheses" do P('Testing#mymethod6').tag(:yield).types.should == ['b', 'a'] end it "should only document the first yield statement in a method (limitation of yield handler)" do P('Testing#mymethod7').tag(:yield).types.should == ['a'] end it "should handle `self` keyword and list object type as yieldparam for _self" do P('Testing#mymethod8').tag(:yield).types.should == ['_self'] P('Testing#mymethod8').tag(:yieldparam).types.should == ['Testing'] P('Testing#mymethod8').tag(:yieldparam).text.should == "the object that the method was called on" end it "should handle `super` keyword and document it under _super" do P('Testing#mymethod9').tag(:yield).types.should == ['_super'] P('Testing#mymethod9').tag(:yieldparam).types.should be_nil P('Testing#mymethod9').tag(:yieldparam).text.should == "the result of the method from the superclass" end endyard-0.8.7.3/spec/templates/0000755000004100000410000000000012261240652015606 5ustar www-datawww-datayard-0.8.7.3/spec/templates/examples/0000755000004100000410000000000012261240652017424 5ustar www-datawww-datayard-0.8.7.3/spec/templates/examples/module004.html0000644000004100000410000001261612261240652022031 0ustar www-datawww-data

                Class: A

                Inherits:
                Object
                • Object
                show all
                Extended by:
                Bar
                Includes:
                BarFooBar, Baz::ABC, Baz::XYZ, Foo
                Defined in:
                (stdin)

                Instance Attribute Summary (collapse)

                Booya (collapse)

                • + baz extended from Bar
                  Docs for baz in Booya group.
                • - baz_abc included from Baz::ABC

                Instance Method Summary (collapse)

                • - foo
                  This method is in A.
                • - xyz included from Foo
                  Docs for xyz.

                Methods included from Baz::XYZ

                #baz_xyz

                Methods included from BarFooBar

                #bar_foo_bar

                Instance Attribute Details

                - bar_attr Originally defined in module Foo

                Docs for bar_attr

                Class Method Details

                + baz Originally defined in module Bar

                Docs for baz in Booya group

                Instance Method Details

                - baz_abc Originally defined in module Baz::ABC

                - foo

                This method is in A
            
            
            3
            # File '(stdin)', line 3
            
            def foo; end

            - xyz Originally defined in module Foo

            Docs for xyz
            yard-0.8.7.3/spec/templates/examples/module001.txt0000644000004100000410000000067312261240652021701 0ustar www-datawww-data-------------------------------------------------------------- Module: A Comments ------------------------------------------------------------------------ Defined Under Namespace: ------------------------ Z (modules) Q, X, Y (classes) Includes: --------- D, E, F, A::B::C, B, BaseMod Class methods: -------------- a Instance methods: ----------------- a, test_multi_overload, test_overload, void_meth yard-0.8.7.3/spec/templates/examples/method005.txt0000644000004100000410000000140512261240652021672 0ustar www-datawww-data------------------------------------------------------------- Method: #m (Defined in: (stdin)) root.m(a) -> void root.m(b) ------------------------------------------------------------------------ Overloads: ---------- ------------------------------------------------------------------------ root.m(a) -> void ------------------------------------------------------------------------ This method returns an undefined value. ------------------------------------------------------------------------ root.m(b) ------------------------------------------------------------------------ Parameters: ----------- (String) b - hi yard-0.8.7.3/spec/templates/examples/method001.html0000644000004100000410000000430612261240652022016 0ustar www-datawww-data

            Method: #m

            Defined in:
            (stdin)

            - (String) m(x) (private) Also known as: x

            Deprecated.
            for great justice
            Comments

            Parameters:

            • x (Hash)
              the x argument

            Options Hash (x):

            • :key1 (String) — default: default
              first key
            • :key2 (Symbol)
              second key

            Returns:

            • (String)
              the result

            Raises:

            • (Exception)
              hi!
            
            
            9
            # File '(stdin)', line 9
            
            def m(x) end
            yard-0.8.7.3/spec/templates/examples/constant002.txt0000644000004100000410000000035512261240652022243 0ustar www-datawww-data------------------------------------------------------ Constant: MYCONST MYCONST = 'foo' ------------------------------------------------------------------------ ------------------------------------------------------------------------yard-0.8.7.3/spec/templates/examples/module002.html0000644000004100000410000001025512261240652022024 0ustar www-datawww-data

            Module: A

            Defined in:
            (stdin)

            Foo (collapse)

            Foo (collapse)

            Bar (collapse)

            Class Method Summary (collapse)

            Instance Attribute Details

            - foo_attr

            Returns the value of attribute foo_attr
            
            
            3
            4
            5
            # File '(stdin)', line 3
            
            def foo_attr
              @foo_attr
            end

            Class Method Details

            + bar

            
            
            5
            # File '(stdin)', line 5
            
            def self.bar; end

            + baz

            
            
            12
            # File '(stdin)', line 12
            
            def self.baz; end

            Instance Method Details

            - baz

            
            
            8
            # File '(stdin)', line 8
            
            def baz; end

            - foo

            
            
            4
            # File '(stdin)', line 4
            
            def foo; end
            yard-0.8.7.3/spec/templates/examples/module001.dot0000644000004100000410000000127312261240652021645 0ustar www-datawww-dataA [label="{module A|+ \#attr1 [RW]\l+ \#attr2 [R]\l+ \#attr3 [RW]\l+ \#attr4 [W]\l|+ a\l+ \#a\l+ \#test_multi_overload\l+ \#test_overload\l+ \#void_meth\ \:\ void\l}" rank=sink]; A_Y [label="{class Y||}" rank=sink]; subgraph cluster_A_Y { label = "Y"; labelloc=b; } A_Q [label="{class Q||}" rank=sink]; subgraph cluster_A_Q { label = "Q"; labelloc=b; } A_X [label="{class X||}" rank=sink]; subgraph cluster_A_X { label = "X"; labelloc=b; } subgraph cluster_A { label = "A"; labelloc=b; A_Z [label="{module Z||}" rank=sink]; subgraph cluster_A_Z { label = "Z"; labelloc=b; } } A -> B [style=dotted arrowType=none]; A -> BaseMod [style=dotted arrowType=none]; yard-0.8.7.3/spec/templates/examples/class001.html0000644000004100000410000001043412261240652021642 0ustar www-datawww-data

            Class: A Abstract

            Inherits:
            B
            • Object
            show all
            Defined in:
            (stdin)

            Overview

            This class is abstract.
            override this class
            Comments

            See Also:

            Author:

            • Test

            Version:

            • 1.0

            Direct Known Subclasses

            C

            Instance Method Summary (collapse)

            Constructor Details

            - (A) initialize(test)

            constructor method!
            
            
            15
            # File '(stdin)', line 15
            
            def initialize(test) end

            Dynamic Method Handling

            This class handles dynamic methods through the method_missing method

            - method_missing(*args)

            HI
            
            
            10
            # File '(stdin)', line 10
            
            def method_missing(*args) end

            Instance Method Details

            - a

            Deprecated.
            
            
            12
            # File '(stdin)', line 12
            
            def a; end
            yard-0.8.7.3/spec/templates/examples/module003.html0000644000004100000410000000457412261240652022034 0ustar www-datawww-data

            Module: A

            Includes:
            B
            Defined in:
            (stdin)

            Constant Summary

            FOO =
            2

            Instance Attribute Summary (collapse)

            • - bar readonly
              Returns the value of attribute bar.

            Instance Method Summary (collapse)

            Instance Attribute Details

            - bar (readonly)

            Returns the value of attribute bar
            
            
            11
            12
            13
            # File '(stdin)', line 11
            
            def bar
              @bar
            end

            Instance Method Details

            - foo

            
            
            10
            # File '(stdin)', line 10
            
            def foo; end
            yard-0.8.7.3/spec/templates/examples/module001.html0000644000004100000410000002612412261240652022025 0ustar www-datawww-data

            Module: A

            Includes:
            B, BaseMod
            Included in:
            TMP, TMP2
            Defined in:
            (stdin)

            Overview

            Comments

            Defined Under Namespace

            Modules: Z Classes: Q, X, Y

            Constant Summary

            CONSTANT =
            A long docstring for the constant. With extra text and newlines.
            'value'
            @@cvar =
            Deprecated.
            'value'

            Instance Attribute Summary (collapse)

            Attributes included from BaseMod

            #base_attr1, #base_attr2, #base_attr3

            Class Method Summary (collapse)

            Instance Method Summary (collapse)

            Methods included from B

            #c, #d

            Instance Attribute Details

            - attr1

            Returns the value of attribute attr1
            
            
            17
            18
            19
            # File '(stdin)', line 17
            
            def attr1
              @attr1
            end

            - attr2 (readonly)

            Returns the value of attribute attr2
            
            
            18
            19
            20
            # File '(stdin)', line 18
            
            def attr2
              @attr2
            end

            - (String) attr3 - attr3=(value)

            Overloads:

            • - (String) attr3
              Returns a string

              Returns:

              • (String)
                a string
            • - attr3=(value)

              This method returns an undefined value.

              Parameters:

              • value (String)
                sets the string
            
            
            25
            26
            27
            # File '(stdin)', line 25
            
            def attr3
              @attr3
            end

            - attr4=(value) (writeonly)

            Sets the attribute attr4

            Parameters:

            • value
              the value to set the attribute attr4 to.
            
            
            27
            28
            29
            # File '(stdin)', line 27
            
            def attr4=(value)
              @attr4 = value
            end

            Class Method Details

            + a

            
            
            29
            # File '(stdin)', line 29
            
            def self.a; end

            Instance Method Details

            - a Also known as: b

            
            
            30
            # File '(stdin)', line 30
            
            def a; end

            - test_multi_overload(a) - test_multi_overload(a, b)

            
            
            40
            # File '(stdin)', line 40
            
            def test_multi_overload(*args) end

            - test_overload(a)

            hello2

            Parameters:

            • a (String)
              hi
            
            
            36
            # File '(stdin)', line 36
            
            def test_overload(*args) end

            - void_meth

            This method returns an undefined value.

            
            
            43
            # File '(stdin)', line 43
            
            def void_meth; end
            yard-0.8.7.3/spec/templates/examples/method005.html0000644000004100000410000000314012261240652022015 0ustar www-datawww-data

            Method: #m

            Defined in:
            (stdin)

            - (void) m(a) - m(b)

            Overloads:

            • - (void) m(a)

              This method returns an undefined value.

            • - m(b)

              Parameters:

              • b (String)
                hi
            
            
            5
            # File '(stdin)', line 5
            
            def m(*args) end
            yard-0.8.7.3/spec/templates/examples/method004.html0000644000004100000410000000142412261240652022017 0ustar www-datawww-data

            Method: #m

            Defined in:
            (stdin)

            - (void) m(*args)

            This method returns an undefined value.

            
            
            2
            # File '(stdin)', line 2
            
            def m(*args) end
            yard-0.8.7.3/spec/templates/examples/method002.html0000644000004100000410000000235512261240652022021 0ustar www-datawww-data

            Method: #m

            Defined in:
            (stdin)

            - m(x, y) (private)

            Comments

            Parameters:

            • x (String)
              parameter x
            • y (Boolean)
              parameter y
            
            
            6
            # File '(stdin)', line 6
            
            def m(x) end
            yard-0.8.7.3/spec/templates/examples/method003.txt0000644000004100000410000000175512261240652021700 0ustar www-datawww-data------------------------------------------------------------- Method: #m (Defined in: (stdin)) root.m(x, y) (private) root.m(x, y, z) (private) ------------------------------------------------------------------------ Method comments Overloads: ---------- ------------------------------------------------------------------------ root.m(x, y) (private) ------------------------------------------------------------------------ Overload docstring Parameters: ----------- (String) x - parameter x (Boolean) y - parameter y ------------------------------------------------------------------------ root.m(x, y, z) (private) ------------------------------------------------------------------------ Parameters: ----------- (String) x - parameter x (Boolean) y - parameter y (Boolean) z - parameter z yard-0.8.7.3/spec/templates/examples/tag001.txt0000644000004100000410000000203512261240652021161 0ustar www-datawww-data------------------------------------------------------------- Method: #m (Defined in: (stdin)) root.m(opts = {}) {|a| ... } -> String ------------------------------------------------------------------------ Deprecated. for great justice Abstract. override me Comments Examples: --------- # Wash your car car.wash # To kill a mockingbird a = String.new flip(a.reverse) Parameters: ----------- (Hash) opts - the options Options Hash (opts): -------------------- (Object) :key - default: '' - hello (Object) :key2 - default: X - hello Yields: ------- - a block Yield Parameters: ----------------- (String) a - a value Yield Returns: -------------- (Hash) - a hash Returns: -------- (String) - the result Raises: ------- (Exception) - Exception class See Also: --------- - A - http://url.com - http://url.com - Example Author: ------- Name Since: ------ 1.0 Version: -------- 1.0 yard-0.8.7.3/spec/templates/examples/class002.html0000644000004100000410000000067012261240652021644 0ustar www-datawww-data

            Class: D

            Inherits:
            Object
            • Object
            show all
            Defined in:
            (stdin)
            yard-0.8.7.3/spec/templates/examples/method004.txt0000644000004100000410000000045312261240652021673 0ustar www-datawww-data------------------------------------------------------------- Method: #m (Defined in: (stdin)) root.m(*args) -> void ------------------------------------------------------------------------ This method returns an undefined value. yard-0.8.7.3/spec/templates/examples/method003.html0000644000004100000410000000461612261240652022024 0ustar www-datawww-data

            Method: #m

            Defined in:
            (stdin)

            - m(x, y) (private) - m(x, y, z) (private)

            Method comments

            Overloads:

            • - m(x, y)
              Overload docstring

              Parameters:

              • x (String)
                parameter x
              • y (Boolean)
                parameter y
            • - m(x, y, z)

              Parameters:

              • x (String)
                parameter x
              • y (Boolean)
                parameter y
              • z (Boolean)
                parameter z
            
            
            11
            # File '(stdin)', line 11
            
            def m(*args) end
            yard-0.8.7.3/spec/templates/examples/class001.txt0000644000004100000410000000070212261240652021512 0ustar www-datawww-data----------------------------------------------------------- Class: A < B Abstract. override this class Comments See Also: --------- - A - http://example.com - Example Author: ------- Test Version: -------- 1.0 ------------------------------------------------------------------------ Direct Known Subclasses: ------------------------ C Instance methods: ----------------- a, initialize, method_missing yard-0.8.7.3/spec/templates/examples/method002.txt0000644000004100000410000000054612261240652021674 0ustar www-datawww-data------------------------------------------------------------- Method: #m (Defined in: (stdin)) root.m(x, y) (private) ------------------------------------------------------------------------ Comments Parameters: ----------- (String) x - parameter x (Boolean) y - parameter y yard-0.8.7.3/spec/templates/examples/method001.txt0000644000004100000410000000120312261240652021662 0ustar www-datawww-data------------------------------------------------------------- Method: #m (Defined in: (stdin)) (Also known as: #x) root.m(x) -> String (private) ------------------------------------------------------------------------ Deprecated. for great justice Comments Parameters: ----------- (Hash) x - the x argument Options Hash (x): ----------------- (String) :key1 - default: default - first key (Symbol) :key2 - second key Returns: -------- (String) - the result Raises: ------- (Exception) - hi! yard-0.8.7.3/spec/templates/examples/constant001.txt0000644000004100000410000000112212261240652022233 0ustar www-datawww-data------------------------- Constant: YARD::CLI::YRI::DEFAULT_SEARCH_PATHS DEFAULT_SEARCH_PATHS = [] ------------------------------------------------------------------------ Default search paths that should be loaded dynamically into YRI. These paths take precedence over all other paths ({SEARCH_PATHS_FILE} and RubyGems paths). To add a path, call: DEFAULT_SEARCH_PATHS.push("/path/to/.yardoc") Returns: -------- (Array) - a list of extra search paths Since: ------ 0.6.0 ------------------------------------------------------------------------yard-0.8.7.3/spec/templates/examples/constant003.txt0000644000004100000410000000050412261240652022240 0ustar www-datawww-data------------------------------------------------------ Constant: MYCONST MYCONST = [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z] ------------------------------------------------------------------------ ------------------------------------------------------------------------yard-0.8.7.3/spec/templates/onefile_spec.rb0000644000004100000410000000322712261240652020572 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' class StringSerializer < YARD::Serializers::Base attr_accessor :files, :string def initialize(files, string) @files = files @string = string end def serialize(object, data) files << object string << data end end describe YARD::Templates::Engine.template(:default, :onefile) do before do Registry.clear if defined?(::Encoding) @eenc, Encoding.default_external = Encoding.default_external, 'ascii-8bit' @ienc, Encoding.default_internal = Encoding.default_internal, 'ascii-8bit' end end after do if defined?(::Encoding) Encoding.default_internal = @ienc Encoding.default_external = @eenc end end def render @files = [] @output = '' YARD.parse_string <<-eof class A # Foo method # @return [String] def foo; end # Bar method # @return [Numeric] def bar; end end eof readme = CodeObjects::ExtraFileObject.new('README', "# This is a code comment\n\n# Top of file\n\n\nclass C; end") Templates::Engine.generate Registry.all(:class), :serializer => StringSerializer.new(@files, @output), :onefile => true, :format => :html, :readme => readme, :files => [readme, CodeObjects::ExtraFileObject.new('LICENSE', 'This is a license!') ] end it "should render html" do render @files.should == ['index.html'] @output.should include("This is a code comment") @output.should include("This is a license!") @output.should include("Class: A") @output.should include("Foo method") @output.should include("Bar method") end end yard-0.8.7.3/spec/templates/constant_spec.rb0000644000004100000410000000264312261240652021003 0ustar www-datawww-datarequire File.dirname(__FILE__) + "/spec_helper" describe YARD::Templates::Engine.template(:default, :constant) do describe 'fully dressed constant' do it "should render text format correctly" do YARD.parse_string <<-'eof' class YARD::CLI::YRI # Default search paths that should be loaded dynamically into YRI. These paths # take precedence over all other paths ({SEARCH_PATHS_FILE} and RubyGems # paths). To add a path, call: # # DEFAULT_SEARCH_PATHS.push("/path/to/.yardoc") # # @return [Array] a list of extra search paths # @since 0.6.0 DEFAULT_SEARCH_PATHS = [] end eof text_equals(Registry.at('YARD::CLI::YRI::DEFAULT_SEARCH_PATHS').format(text_options), :constant001) end end describe 'simple constant with no documentation' do it "should render text format correctly" do # Short constant should show on single line YARD.parse_string <<-'eof' MYCONST = 'foo' eof text_equals(Registry.at('MYCONST').format(text_options), :constant002) # Long constant should show on multiple lines, indented YARD.parse_string <<-'eof' MYCONST = [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z] eof text_equals(Registry.at('MYCONST').format(text_options), :constant003) end end endyard-0.8.7.3/spec/templates/module_spec.rb0000644000004100000410000000766612261240652020451 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::Templates::Engine.template(:default, :module) do before do Registry.clear YARD.parse_string <<-'eof' module B def c; end def d; end private def e; end end module BaseMod attr_reader :base_attr1 attr_writer :base_attr2 attr_accessor :base_attr3 end # Comments module A include BaseMod attr_accessor :attr1 attr_reader :attr2 # @overload attr3 # @return [String] a string # @overload attr3=(value) # @param [String] value sets the string # @return [void] attr_accessor :attr3 attr_writer :attr4 def self.a; end def a; end alias b a # @overload test_overload(a) # hello2 # @param [String] a hi def test_overload(*args) end # @overload test_multi_overload(a) # @overload test_multi_overload(a, b) def test_multi_overload(*args) end # @return [void] def void_meth; end include B class Y; end class Q; end class X; end module Z; end # A long docstring for the constant. With extra text # and newlines. CONSTANT = 'value' @@cvar = 'value' # @deprecated end module TMP; include A end class TMP2; extend A end eof end it "should render html format correctly" do html_equals(Registry.at('A').format(html_options(:hide_void_return => true, :verifier => Verifier.new('object.type != :method || object.visibility == :public'))), :module001) end it "should render text format correctly" do YARD.parse_string <<-'eof' module A include D, E, F, A::B::C end eof text_equals(Registry.at('A').format(text_options), :module001) end it "should render dot format correctly" do Registry.at('A').format(:format => :dot, :dependencies => true, :full => true).should == example_contents(:module001, 'dot') end it "should render groups correctly in html" do Registry.clear YARD.parse_string <<-'eof' module A # @group Foo attr_accessor :foo_attr def foo; end def self.bar; end # @group Bar def baz; end # @endgroup def self.baz; end end eof html_equals(Registry.at('A').format(html_options), :module002) end it "should ignore overwritten/private attributes/constants from inherited list" do Registry.clear YARD.parse_string <<-'eof' module B attr_reader :foo attr_accessor :bar # @private attr_writer :baz FOO = 1 end module A include B def foo; end attr_reader :bar FOO = 2 end eof html_equals(Registry.at('A').format(html_options( :verifier => Verifier.new('!@private'))), :module003) end it "should embed mixins with :embed_mixins = ['Foo', 'Bar', 'Baz::A*']" do Registry.clear YARD.parse_string <<-'eof' class A # This method is in A def foo; end include Foo extend Bar include BarFooBar include Baz::XYZ include Baz::ABC end module BarFooBar def bar_foo_bar; end end module Foo def self.not_included; end # Docs for xyz def xyz; end # Docs for bar_attr attr_accessor :bar_attr end module Bar def self.not_included; end # @group Booya # Docs for baz in Booya group def baz; end end module Baz module XYZ # listed as inherited def baz_xyz; end end module ABC def baz_abc; end end end eof html_equals(Registry.at('A').format(html_options(:embed_mixins => ['Foo', 'Bar', 'Baz::A*'])), :module004) end end yard-0.8.7.3/spec/templates/class_spec.rb0000644000004100000410000000177612261240652020265 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::Templates::Engine.template(:default, :docstring) do before do Registry.clear YARD.parse_string <<-'eof' private # Comments # @abstract override this class # @author Test # @version 1.0 # @see A # @see http://example.com Example class A < B # HI def method_missing(*args) end # @deprecated def a; end # constructor method! def initialize(test) end end class C < A; end class D # @private def initialize; end end eof end it "should render html format correctly" do html_equals(Registry.at('A').format(html_options), :class001) end it "should render text format correctly" do text_equals(Registry.at('A').format, :class001) end it "should hide private constructors" do html_equals(Registry.at('D').format(html_options(:verifier => Verifier.new("!@private"))), :class002) end end yard-0.8.7.3/spec/templates/spec_helper.rb0000644000004100000410000000333712261240652020432 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' include YARD::Templates def only_copy?(result, example, type) if $COPY == :all || $COPY == example puts(result) unless $COPYT && $COPYT != type end $COPY ? true : false end def text_equals(result, expected_example) return if only_copy?(result, expected_example, :text) text_equals_string(result, example_contents(expected_example, :txt)) end def text_equals_string(result, expected) result.should == expected end def html_equals(result, expected_example) return if only_copy?(result, expected_example, :html) html_equals_string(result, example_contents(expected_example)) end def html_equals_string(result, expected) [expected, result].each do |value| value.gsub!(/(>)\s+|\s+(<)/, '\1\2') value.gsub!(/'/, "'") value.strip! end text_equals_string(result, expected) end def example_contents(filename, ext = 'html') File.read(File.join(File.dirname(__FILE__), 'examples', "#{filename}.#{ext}")) end module YARD::Templates::Engine class << self public :find_template_paths end end class TestHtmlTemplateOptions < Templates::TemplateOptions default_attr :markup, :none default_attr :default_return, "" default_attr :format, :html default_attr :highlight, false end class TestTextTemplateOptions < Templates::TemplateOptions default_attr :markup, :none default_attr :default_return, "" default_attr :format, :text default_attr :highlight, false end def html_options(opts = {}) template_options(opts, TestHtmlTemplateOptions) end def text_options(opts = {}) template_options(opts, TestTextTemplateOptions) end def template_options(opts, klass) options = klass.new options.reset_defaults options.update(opts) options end yard-0.8.7.3/spec/templates/section_spec.rb0000644000004100000410000001043412261240652020613 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::Templates::Section do include YARD::Templates describe '#initialize' do it "should convert first argument to splat if it is array" do s = Section.new(:name, [:foo, :bar]) s.name.should == :name s[0].name.should == :foo s[1].name.should == :bar end it "should allow initialization with Section objects" do s = Section.new(:name, [:foo, Section.new(:bar)]) s.name.should == :name s[0].should == Section.new(:foo) s[1].should == Section.new(:bar) end it "should make a list of sections" do s = Section.new(:name, [:foo, [:bar]]) s.should == Section.new(:name, Section.new(:foo, Section.new(:bar))) end end describe '#[]' do it "should use Array#[] if argument is integer" do Section.new(:name, [:foo, :bar])[0].name.should == :foo end it "should return new Section object if more than one argument" do Section.new(:name, :foo, :bar, :baz)[1, 2].should == Section.new(:name, :bar, :baz) end it "should return new Section object if arg is Range" do Section.new(:name, :foo, :bar, :baz)[1..2].should == Section.new(:name, :bar, :baz) end it "should look for section by name if arg is object" do Section.new(:name, :foo, :bar, [:baz])[:bar][:baz].should == Section.new(:baz) end end describe '#eql?' do it "should check for equality of two equal sections" do Section.new(:foo, [:a, :b]).should be_eql(Section.new(:foo, :a, :b)) Section.new(:foo, [:a, :b]).should == Section.new(:foo, :a, :b) end it "should not be equal if section names are different" do Section.new(:foo, [:a, :b]).should_not be_eql(Section.new(:bar, :a, :b)) Section.new(:foo, [:a, :b]).should_not == Section.new(:bar, :a, :b) end end describe '#==' do it "should allow comparison to Symbol" do Section.new(:foo, 2, 3).should == :foo end it "should allow comparison to String" do Section.new("foo", 2, 3).should == "foo" end it "should allow comparison to Template" do t = YARD::Templates::Engine.template!(:xyzzy, '/full/path/xyzzy') Section.new(t, 2, 3).should == t end it "should allow comparison to Section" do Section.new(1, [2, 3]).should == Section.new(1, 2, 3) end it "should allow comparison to Object" do Section.new(1, [2, 3]).should == 1 end it "should allow comparison to Array" do Section.new(1, 2, [3]).should == [1, [2, [3]]] end end describe '#to_a' do it "should convert Section to regular Array list" do arr = Section.new(1, 2, [3, [4]]).to_a arr.class.should == Array arr.should == [1, [2, [3, [4]]]] end end describe '#place' do it "should place objects as Sections" do Section.new(1, 2, 3).place(4).before(3).should == [1, [2, 4, 3]] end it "should place objects anywhere inside Section with before/after_any" do Section.new(1, 2, [3, [4]]).place(5).after_any(4).should == [1, [2, [3, [4, 5]]]] Section.new(1, 2, [3, [4]]).place(5).before_any(4).should == [1, [2, [3, [5, 4]]]] end it "should allow multiple sections to be placed" do Section.new(1, 2, 3).place(4, 5).after(3).to_a.should == [1, [2, 3, 4, 5]] Section.new(1, 2, 3).place(4, [5]).after(3).to_a.should == [1, [2, 3, 4, [5]]] end end describe '#push' do it "should push objects as Sections" do s = Section.new(:foo) s.push :bar s[0].should == Section.new(:bar) end it "should alias to #<<" do s = Section.new(1) s << :index s[:index].should be_a(Section) end end describe '#unshift' do it "should unshift objects as Sections" do s = Section.new(:foo) s.unshift :bar s[0].should == Section.new(:bar) end end describe '#any' do it "should find item inside sections" do s = Section.new(:foo, Section.new(:bar, Section.new(:bar))) s.any(:bar).push(:baz) s.to_a.should == [:foo, [:bar, [:bar, :baz]]] end it "should find item in any deeply nested set of sections" do s = Section.new(:foo, Section.new(:bar, Section.new(:baz))) s.any(:baz).push(:qux) s.to_a.should == [:foo, [:bar, [:baz, [:qux]]]] end end endyard-0.8.7.3/spec/templates/method_spec.rb0000644000004100000410000000462112261240652020430 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' # $COPY = :method001 # $COPYT = :html describe YARD::Templates::Engine.template(:default, :method) do before { Registry.clear } shared_examples_for "all formats" do it "should render html format correctly" do html_equals(Registry.at('#m').format(html_options), @template) end it "should render text format correctly" do text_equals(Registry.at('#m').format(text_options), @template) end end describe 'regular (deprecated) method' do before do @template = :method001 YARD.parse_string <<-'eof' private # Comments # @param [Hash] x the x argument # @option x [String] :key1 (default) first key # @option x [Symbol] :key2 second key # @return [String] the result # @raise [Exception] hi! # @deprecated for great justice def m(x) end alias x m eof end it_should_behave_like "all formats" end describe 'method with 1 overload' do before do @template = :method002 YARD.parse_string <<-'eof' private # Comments # @overload m(x, y) # @param [String] x parameter x # @param [Boolean] y parameter y def m(x) end eof end it_should_behave_like "all formats" end describe 'method with 2 overloads' do before do @template = :method003 YARD.parse_string <<-'eof' private # Method comments # @overload m(x, y) # Overload docstring # @param [String] x parameter x # @param [Boolean] y parameter y # @overload m(x, y, z) # @param [String] x parameter x # @param [Boolean] y parameter y # @param [Boolean] z parameter z def m(*args) end eof end it_should_behave_like "all formats" end describe 'method void return' do before do @template = :method004 YARD.parse_string <<-'eof' # @return [void] def m(*args) end eof end it_should_behave_like "all formats" end describe 'method void return in an overload' do before do @template = :method005 YARD.parse_string <<-'eof' # @overload m(a) # @return [void] # @overload m(b) # @param [String] b hi def m(*args) end eof end it_should_behave_like "all formats" end endyard-0.8.7.3/spec/templates/helpers/0000755000004100000410000000000012261240652017250 5ustar www-datawww-datayard-0.8.7.3/spec/templates/helpers/markup/0000755000004100000410000000000012261240652020547 5ustar www-datawww-datayard-0.8.7.3/spec/templates/helpers/markup/rdoc_markup_spec.rb0000644000004100000410000000577712261240652024434 0ustar www-datawww-datarequire File.dirname(__FILE__) + "/../../spec_helper" describe YARD::Templates::Helpers::Markup::RDocMarkup do describe 'loading mechanism' do before { @good_libs = [] } def require(lib) return true if @good_libs.include?(lib) raise LoadError end def load_markup begin require 'rdoc/markup' require 'rdoc/markup/to_html' return :RDoc2 rescue LoadError begin require 'rdoc/markup/simple_markup' require 'rdoc/markup/simple_markup/to_html' return :RDoc1 rescue LoadError raise NameError, "could not load RDocMarkup (rdoc is not installed)" end end end it "should load RDoc2.x if rdoc/markup is present" do @good_libs += ['rdoc/markup', 'rdoc/markup/to_html'] load_markup.should == :RDoc2 end it "should fail on RDoc2.x if rdoc/markup/to_html is not present" do @good_libs += ['rdoc/markup'] lambda { load_markup }.should raise_error(NameError) end it "should load RDoc1.x if RDoc2 fails and rdoc/markup/simple_markup is present" do @good_libs += ['rdoc/markup/simple_markup', 'rdoc/markup/simple_markup/to_html'] load_markup.should == :RDoc1 end it "should error on loading if neither lib is present" do lambda { load_markup }.should raise_error(NameError) end end describe '#to_html' do def to_html(text) html = YARD::Templates::Helpers::Markup::RDocMarkup.new(text).to_html html.strip.gsub(/\r?\n/, '') end it 'handles typewriter text' do to_html('Hello ++').should == '

            Hello <code>

            ' end end describe '#fix_typewriter' do def fix_typewriter(text) YARD::Templates::Helpers::Markup::RDocMarkup.new('').send(:fix_typewriter, text) end it "should use #fix_typewriter to convert +text+ to text" do fix_typewriter("Some +typewriter text <+.").should == "Some typewriter text <." fix_typewriter("Not +typewriter text.").should == "Not +typewriter text." fix_typewriter("Alternating +type writer+ text +here+.").should == "Alternating type writer text here." fix_typewriter("No ++problem.").should == "No ++problem." fix_typewriter("Math + stuff +is ok+").should == "Math + stuff is ok" fix_typewriter("Hello +{Foo}+ World").should == "Hello {Foo} World" end it "should not apply to code blocks" do fix_typewriter("Hello +hello+").should == "Hello +hello+" end it "should not apply to HTML tag attributes" do fix_typewriter("A+b+c").should == "A+b+c" fix_typewriter("").should == "" end it "should still apply inside of other tags" do fix_typewriter("

            +foo+

            ").should == "

            foo

            " end end endyard-0.8.7.3/spec/templates/helpers/shared_signature_examples.rb0000644000004100000410000000676512261240652025040 0ustar www-datawww-datashared_examples_for "signature" do before do YARD::Registry.clear @options = Templates::TemplateOptions.new @options.reset_defaults stub!(:options).and_return(@options) end it "should show signature for regular instance method" do YARD.parse_string "def foo; end" signature(Registry.at('#foo')).should == @results[:regular] end it "should allow default return type to be changed" do @options.default_return = "Hello" YARD.parse_string "def foo; end" signature(Registry.at('#foo')).should == @results[:default_return] end it "should allow default return type to be omitted" do @options.default_return = "" YARD.parse_string "def foo; end" signature(Registry.at('#foo')).should == @results[:no_default_return] end it "should show signature for private class method" do YARD.parse_string "class A; private; def self.foo; end end" signature(Registry.at('A.foo')).should == @results[:private_class] end it "should show return type for single type" do YARD.parse_string <<-'eof' # @return [String] def foo; end eof signature(Registry.at('#foo')).should == @results[:single] end it "should show return type for 2 types" do YARD.parse_string <<-'eof' # @return [String, Symbol] def foo; end eof signature(Registry.at('#foo')).should == @results[:two_types] end it "should show return type for 2 types over multiple tags" do YARD.parse_string <<-'eof' # @return [String] # @return [Symbol] def foo; end eof signature(Registry.at('#foo')).should == @results[:two_types_multitag] end it "should show 'Type?' if return types are [Type, nil]" do YARD.parse_string <<-'eof' # @return [Type, nil] def foo; end eof signature(Registry.at('#foo')).should == @results[:type_nil] end it "should show 'Type?' if return types are [Type, nil, nil] (extra nil)" do YARD.parse_string <<-'eof' # @return [Type, nil] # @return [nil] def foo; end eof signature(Registry.at('#foo')).should == @results[:type_nil] end it "should show 'Type+' if return types are [Type, Array]" do YARD.parse_string <<-'eof' # @return [Type, ] def foo; end eof signature(Registry.at('#foo')).should == @results[:type_array] end it "should (Type, ...) for more than 2 return types" do YARD.parse_string <<-'eof' # @return [Type, ] # @return [AnotherType] def foo; end eof signature(Registry.at('#foo')).should == @results[:multitype] end it "should show (void) for @return [void] by default" do YARD.parse_string <<-'eof' # @return [void] def foo; end eof signature(Registry.at('#foo')).should == @results[:void] end it "should not show return for @return [void] if :hide_void_return is true" do @options.hide_void_return = true YARD.parse_string <<-'eof' # @return [void] def foo; end eof signature(Registry.at('#foo')).should == @results[:hide_void] end it "should show block for method with yield" do YARD.parse_string <<-'eof' def foo; yield(a, b, c) end eof signature(Registry.at('#foo')).should == @results[:block] end it "should use regular return tag if the @overload is empty" do YARD.parse_string <<-'eof' # @overload foobar # Hello world # @return [String] def foo; end eof signature(Registry.at('#foo').tag(:overload)).should == @results[:empty_overload] end end yard-0.8.7.3/spec/templates/helpers/markup_helper_spec.rb0000644000004100000410000001231512261240652023447 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../../spec_helper' module YARD::Templates::Helpers::MarkupHelper public :load_markup_provider, :markup_class, :markup_provider end class GeneratorMock attr_accessor :options include YARD::Templates::Helpers::MarkupHelper def initialize(options = Templates::TemplateOptions.new) self.options = options end end describe YARD::Templates::Helpers::MarkupHelper do before do YARD::Templates::Helpers::MarkupHelper.clear_markup_cache end describe '#load_markup_provider' do before do log.stub!(:error) @gen = GeneratorMock.new @gen.options.reset_defaults end it "should exit on an invalid markup type" do @gen.options.markup = :invalid @gen.load_markup_provider.should == false end it "should fail on when an invalid markup provider is specified" do @gen.options.update(:markup => :markdown, :markup_provider => :invalid) @gen.load_markup_provider.should == false @gen.markup_class.should == nil end it "should load RDocMarkup if rdoc is specified and it is installed" do @gen.options.markup = :rdoc @gen.load_markup_provider.should == true @gen.markup_class.should == YARD::Templates::Helpers::Markup::RDocMarkup end it "should fail if RDoc cannot be loaded" do @gen.options.markup = :rdoc @gen.should_receive(:eval).with('::YARD::Templates::Helpers::Markup::RDocMarkup').and_raise(NameError) @gen.load_markup_provider.should == false @gen.markup_provider.should == nil end it "should search through available markup providers for the markup type if none is set" do @gen.should_receive(:eval).with('::RedcarpetCompat').and_return(mock(:bluecloth)) @gen.should_receive(:require).with('redcarpet').and_return(true) @gen.should_not_receive(:require).with('maruku') @gen.options.markup = :markdown # this only raises an exception because we mock out require to avoid # loading any libraries but our implementation tries to return the library # name as a constant @gen.load_markup_provider.should == true @gen.markup_provider.should == :redcarpet end it "should continue searching if some of the providers are unavailable" do @gen.should_receive(:require).with('redcarpet').and_raise(LoadError) @gen.should_receive(:require).with('rdiscount').and_raise(LoadError) @gen.should_receive(:require).with('kramdown').and_raise(LoadError) @gen.should_receive(:require).with('bluecloth').and_raise(LoadError) @gen.should_receive(:require).with('maruku').and_raise(LoadError) @gen.should_receive(:require).with('rpeg-markdown').and_return(true) @gen.should_receive(:eval).with('::PEGMarkdown').and_return(true) @gen.options.markup = :markdown # this only raises an exception because we mock out require to avoid # loading any libraries but our implementation tries to return the library # name as a constant @gen.load_markup_provider.should rescue nil @gen.markup_provider.should == :"rpeg-markdown" end it "should override the search if `:markup_provider` is set in options" do @gen.should_receive(:require).with('rdiscount').and_return(true) @gen.should_receive(:eval).with('::RDiscount').and_return(true) @gen.options.update(:markup => :markdown, :markup_provider => :rdiscount) @gen.load_markup_provider.should rescue nil @gen.markup_provider.should == :rdiscount end it "should fail if no provider is found" do YARD::Templates::Helpers::MarkupHelper::MARKUP_PROVIDERS[:markdown].each do |p| @gen.should_receive(:require).with(p[:lib].to_s).and_raise(LoadError) end @gen.options.markup = :markdown @gen.load_markup_provider.should == false @gen.markup_provider.should == nil end it "should fail if overridden provider is not found" do @gen.should_receive(:require).with('rdiscount').and_raise(LoadError) @gen.options.update(:markup => :markdown, :markup_provider => :rdiscount) @gen.load_markup_provider.should == false @gen.markup_provider.should == nil end it "should fail if the markup type is not found" do log.should_receive(:error).with(/Invalid markup/) @gen.options.markup = :xxx @gen.load_markup_provider.should == false @gen.markup_provider.should == nil end end describe '#markup_for_file' do include YARD::Templates::Helpers::MarkupHelper it "should look for a shebang line" do markup_for_file("#!text\ntext here", 'file.rdoc').should == :text end it "should return the default markup type if no shebang is found or no valid ext is found" do stub!(:options).and_return(Options.new.update(:markup => :default_type)) markup_for_file('', 'filename').should == :default_type end it "should look for a file extension if no shebang is found" do markup_for_file('', 'filename.MD').should == :markdown end Templates::Helpers::MarkupHelper::MARKUP_EXTENSIONS.each do |type, exts| exts.each do |ext| it "should recognize .#{ext} as #{type} markup type" do markup_for_file('', "filename.#{ext}").should == type end end end end end yard-0.8.7.3/spec/templates/helpers/method_helper_spec.rb0000644000004100000410000000456412261240652023437 0ustar www-datawww-datarequire File.dirname(__FILE__) + "/../spec_helper" describe YARD::Templates::Helpers::MethodHelper do include YARD::Templates::Helpers::BaseHelper include YARD::Templates::Helpers::MethodHelper describe '#format_args' do it "should display keyword arguments" do params = [['a:', '1'], ['b:', '2'], ['**kwargs', nil]] YARD.parse_string 'def foo; end' Registry.at('#foo').stub(:parameters) { params } format_args(Registry.at('#foo')).should == '(a: 1, b: 2, **kwargs)' end it "should not show &blockarg if no @param tag and has @yield" do YARD.parse_string <<-'eof' # @yield blah def foo(&block); end eof format_args(Registry.at('#foo')).should == '' end it "should not show &blockarg if no @param tag and has @yieldparam" do YARD.parse_string <<-'eof' # @yieldparam blah test def foo(&block); end eof format_args(Registry.at('#foo')).should == '' end it "should show &blockarg if @param block is documented (even with @yield)" do YARD.parse_string <<-'eof' # @yield [a,b] # @yieldparam a test # @param block test def foo(&block) end eof format_args(Registry.at('#foo')).should == '(&block)' end end describe '#format_block' do before { YARD::Registry.clear } it "should show block for method with yield" do YARD.parse_string <<-'eof' def foo; yield(a, b, c) end eof format_block(Registry.at('#foo')).should == "{|a, b, c| ... }" end it "should show block for method with @yieldparam tags" do YARD.parse_string <<-'eof' # @yieldparam _self me! def foo; end eof format_block(Registry.at('#foo')).should == "{|_self| ... }" end it "should show block for method with @yield but no types" do YARD.parse_string <<-'eof' # @yield blah # @yieldparam a def foo; end # @yield blah def foo2; end eof format_block(Registry.at('#foo')).should == "{|a| ... }" format_block(Registry.at('#foo2')).should == "{ ... }" end it "should show block for method with @yield and types" do YARD.parse_string <<-'eof' # @yield [a, b, c] blah # @yieldparam a def foo; end eof format_block(Registry.at('#foo')).should == "{|a, b, c| ... }" end end endyard-0.8.7.3/spec/templates/helpers/html_helper_spec.rb0000644000004100000410000005720712261240652023125 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../../spec_helper' require File.dirname(__FILE__) + "/shared_signature_examples" require 'ostruct' describe YARD::Templates::Helpers::HtmlHelper do include YARD::Templates::Helpers::BaseHelper include YARD::Templates::Helpers::HtmlHelper include YARD::Templates::Helpers::MethodHelper def options Templates::TemplateOptions.new.tap do |o| o.reset_defaults o.default_return = nil end end describe '#h' do it "should use #h to escape HTML" do h('Usage: foo "bar" ').should == "Usage: foo "bar" <baz>" end end describe '#charset' do it "should return foo if LANG=foo" do ENV.should_receive(:[]).with('LANG').and_return('shift_jis') if YARD.ruby18? Encoding.default_external.should_receive(:name).and_return('shift_jis') if defined?(Encoding) charset.should == 'shift_jis' end ['US-ASCII', 'ASCII-7BIT', 'ASCII-8BIT'].each do |type| it "should convert #{type} to iso-8859-1" do ENV.should_receive(:[]).with('LANG').and_return(type) if YARD.ruby18? Encoding.default_external.should_receive(:name).and_return(type) if defined?(Encoding) charset.should == 'iso-8859-1' end end it "should support utf8 as an encoding value for utf-8" do type = 'utf8' ENV.should_receive(:[]).with('LANG').and_return(type) if YARD.ruby18? Encoding.default_external.should_receive(:name).and_return(type) if defined?(Encoding) charset.should == 'utf-8' end it "should take file encoding if there is a file" do @file = OpenStruct.new(:contents => 'foo'.force_encoding('sjis')) # not the correct charset name, but good enough ['Shift_JIS', 'Windows-31J'].should include(charset) end if YARD.ruby19? it "should take file encoding if there is a file" do ENV.stub!(:[]).with('LANG').and_return('utf-8') if YARD.ruby18? @file = OpenStruct.new(:contents => 'foo') charset.should == 'utf-8' end if YARD.ruby18? if YARD.ruby18? it "should return utf-8 if no LANG env is set" do ENV.should_receive(:[]).with('LANG').and_return(nil) charset.should == 'utf-8' end it "should only return charset part of lang" do ENV.should_receive(:[]).with('LANG').and_return('en_US.UTF-8') charset.should == 'utf-8' end end end describe '#format_types' do it "should include brackets by default" do text = ["String"] should_receive(:linkify).at_least(1).times.with("String", "String").and_return("String") format_types(text).should == format_types(text, true) format_types(text).should == "(String)" end it "should avoid brackets if brackets=false" do should_receive(:linkify).with("String", "String").and_return("String") should_receive(:linkify).with("Symbol", "Symbol").and_return("Symbol") format_types(["String", "Symbol"], false).should == "String, Symbol" end { "String" => [["String"], "String"], "A::B::C" => [["A::B::C"], "A::B::C"], "Array" => [["Array", "String"], "Array<String>"], "Array" => [["Array", "String", "Symbol"], "Array<String, Symbol>"], "Array<{String => Array}>" => [["Array", "String", "Array", "Symbol"], "Array<{String => " + "Array<Symbol>}>"] }.each do |text, values| it "should link all classes in #{text}" do should_receive(:h).with('<').at_least(text.count('<')).times.and_return("<") should_receive(:h).with('>').at_least(text.count('>')).times.and_return(">") values[0].each {|v| should_receive(:linkify).with(v, v).and_return("#{v}") } format_types([text], false).should == values[1] end end end describe '#htmlify' do it "should not use hard breaks for textile markup (RedCloth specific)" do begin; require 'redcloth'; rescue LoadError; pending 'test requires redcloth gem' end htmlify("A\nB", :textile).should_not include("", :pre).should == "
            fo\no\n\nbar<>
            " end it "should return regular text with :text markup" do htmlify("fo\no\n\nbar<>", :text).should == "fo
            o

            bar<>" end it "should return unmodified text with :none markup" do htmlify("fo\no\n\nbar<>", :none).should == "fo\no\n\nbar<>" end it "should highlight ruby if markup is :ruby" do htmlify("class Foo; end", :ruby).should =~ /\A

            HI

            " end it "should autolink URLs (markdown specific)" do log.enter_level(Logger::FATAL) do unless markup_class(:markdown).to_s == "RedcarpetCompat" pending 'This test depends on a markdown engine that supports autolinking' end end htmlify('http://example.com', :markdown).chomp.gsub('/', '/').should == '

            http://example.com

            ' end it "should not autolink URLs inside of {} (markdown specific)" do log.enter_level(Logger::FATAL) do pending 'This test depends on markdown' unless markup_class(:markdown) end htmlify('{http://example.com Title}', :markdown).chomp.should =~ %r{

            Title

            } htmlify('{http://example.com}', :markdown).chomp.should =~ %r{

            http://example.com

            } end end describe "#link_object" do before do stub!(:object).and_return(CodeObjects::NamespaceObject.new(nil, :YARD)) end it "should return the object path if there's no serializer and no title" do stub!(:serializer).and_return nil link_object(CodeObjects::NamespaceObject.new(nil, :YARD)).should == "YARD" end it "should return the title if there's a title but no serializer" do stub!(:serializer).and_return nil link_object(CodeObjects::NamespaceObject.new(nil, :YARD), 'title').should == "title" end it "should link objects from overload tag" do YARD.parse_string <<-'eof' module Foo class Bar; def a; end end class Baz # @overload a def a; end end end eof obj = Registry.at('Foo::Baz#a').tag(:overload) foobar = Registry.at('Foo::Bar') foobaz = Registry.at('Foo::Baz') serializer = Serializers::FileSystemSerializer.new stub!(:serializer).and_return(serializer) stub!(:object).and_return(obj) link_object("Bar#a").should =~ %r{href="Bar.html#a-instance_method"} end it "should use relative path in title" do CodeObjects::ModuleObject.new(:root, :YARD) CodeObjects::ClassObject.new(P('YARD'), :Bar) stub!(:object).and_return(CodeObjects::ModuleObject.new(P('YARD'), :Foo)) serializer = Serializers::FileSystemSerializer.new stub!(:serializer).and_return(serializer) link_object("Bar").should =~ %r{>Bar} end it "should use #title if overridden" do CodeObjects::ModuleObject.new(:root, :YARD) CodeObjects::ClassObject.new(P('YARD'), :Bar) Registry.at('YARD::Bar').stub(:title).and_return('TITLE!') stub!(:object).and_return(Registry.at('YARD::Bar')) serializer = Serializers::FileSystemSerializer.new stub!(:serializer).and_return(serializer) link_object("Bar").should =~ %r{>TITLE!} end it "should use relative path to parent class in title" do root = CodeObjects::ModuleObject.new(:root, :YARD) obj = CodeObjects::ModuleObject.new(root, :SubModule) stub!(:object).and_return(obj) serializer = Serializers::FileSystemSerializer.new stub!(:serializer).and_return(serializer) link_object("YARD").should =~ %r{>YARD} end it "should use Klass.foo when linking to class method in current namespace" do root = CodeObjects::ModuleObject.new(:root, :Klass) obj = CodeObjects::MethodObject.new(root, :foo, :class) stub!(:object).and_return(root) serializer = Serializers::FileSystemSerializer.new stub!(:serializer).and_return(serializer) link_object("foo").should =~ %r{>Klass.foo} end it "should escape method name in title" do YARD.parse_string <<-'eof' class Array def &(other) end end eof obj = Registry.at('Array#&') serializer = Serializers::FileSystemSerializer.new stub!(:serializer).and_return(serializer) stub!(:object).and_return(obj) link_object("Array#&").should =~ %r{title="Array#& \(method\)"} end end describe '#url_for' do before { Registry.clear } it "should return nil if serializer is nil" do stub!(:serializer).and_return nil stub!(:object).and_return Registry.root url_for(P("Mod::Class#meth")).should be_nil end it "should return nil if object is hidden" do yard = CodeObjects::ModuleObject.new(:root, :YARD) stub!(:serializer).and_return Serializers::FileSystemSerializer.new stub!(:object).and_return Registry.root stub!(:options).and_return OpenStruct.new(:verifier => Verifier.new('false')) url_for(yard).should be_nil end it "should return nil if serializer does not implement #serialized_path" do stub!(:serializer).and_return Serializers::Base.new stub!(:object).and_return Registry.root url_for(P("Mod::Class#meth")).should be_nil end it "should link to a path/file for a namespace object" do stub!(:serializer).and_return Serializers::FileSystemSerializer.new stub!(:object).and_return Registry.root yard = CodeObjects::ModuleObject.new(:root, :YARD) url_for(yard).should == 'YARD.html' end it "should link to the object's namespace path/file and use the object as the anchor" do stub!(:serializer).and_return Serializers::FileSystemSerializer.new stub!(:object).and_return Registry.root yard = CodeObjects::ModuleObject.new(:root, :YARD) meth = CodeObjects::MethodObject.new(yard, :meth) url_for(meth).should == 'YARD.html#meth-instance_method' end it "should properly urlencode methods with punctuation in links" do obj = CodeObjects::MethodObject.new(nil, :/) serializer = mock(:serializer) serializer.stub!(:serialized_path).and_return("file.html") stub!(:serializer).and_return(serializer) stub!(:object).and_return(obj) url_for(obj).should == "#%2F-instance_method" end end describe '#anchor_for' do it "should not urlencode data when called directly" do obj = CodeObjects::MethodObject.new(nil, :/) anchor_for(obj).should == "/-instance_method" end end describe '#resolve_links' do def parse_link(link) results = {} link =~ /(.+?)<\/a>/m params, results[:inner_text] = $1, $2 params.scan(/\s*(\S+?)=['"](.+?)['"]\s*/).each do |key, value| results[key.to_sym] = value.gsub(/^["'](.+)["']$/, '\1') end results end it "should escape {} syntax with backslash (\\{foo bar})" do input = '\{foo bar} \{XYZ} \{file:FOO} $\{N-M}' output = '{foo bar} {XYZ} {file:FOO} ${N-M}' resolve_links(input).should == output end it "should escape {} syntax with ! (!{foo bar})" do input = '!{foo bar} !{XYZ} !{file:FOO} $!{N-M}' output = '{foo bar} {XYZ} {file:FOO} ${N-M}' resolve_links(input).should == output end it "should link static files with file: prefix" do stub!(:serializer).and_return Serializers::FileSystemSerializer.new stub!(:object).and_return Registry.root parse_link(resolve_links("{file:TEST.txt#abc}")).should == { :inner_text => "TEST", :title => "TEST", :href => "file.TEST.html#abc" } parse_link(resolve_links("{file:TEST.txt title}")).should == { :inner_text => "title", :title => "title", :href => "file.TEST.html" } end it "should create regular links with http:// or https:// prefixes" do parse_link(resolve_links("{http://example.com}")).should == { :inner_text => "http://example.com", :target => "_parent", :href => "http://example.com", :title => "http://example.com" } parse_link(resolve_links("{http://example.com title}")).should == { :inner_text => "title", :target => "_parent", :href => "http://example.com", :title => "title" } end it "should create mailto links with mailto: prefixes" do parse_link(resolve_links('{mailto:joanna@example.com}')).should == { :inner_text => 'mailto:joanna@example.com', :target => '_parent', :href => 'mailto:joanna@example.com', :title => 'mailto:joanna@example.com' } parse_link(resolve_links('{mailto:steve@example.com Steve}')).should == { :inner_text => 'Steve', :target => '_parent', :href => 'mailto:steve@example.com', :title => 'Steve' } end it "should ignore {links} that begin with |...|" do resolve_links("{|x|x == 1}").should == "{|x|x == 1}" end it "should gracefully ignore {} in links" do should_receive(:linkify).with('Foo', 'Foo').and_return('FOO') resolve_links("{} {} {Foo Foo}").should == '{} {} FOO' end %w(tt code pre).each do |tag| it "should ignore links in <#{tag}>" do text = "<#{tag}>{Foo}" resolve_links(text).should == text end end it "should resolve {Name}" do should_receive(:link_file).with('TEST', nil, nil).and_return('') resolve_links("{file:TEST}") end it "should resolve ({Name})" do should_receive(:link_file).with('TEST', nil, nil).and_return('') resolve_links("({file:TEST})") end it "should resolve link with newline in title-part" do parse_link(resolve_links("{http://example.com foo\nbar}")).should == { :inner_text => "foo bar", :target => "_parent", :href => "http://example.com", :title => "foo bar" } end it "should resolve links to methods whose names have been escaped" do should_receive(:linkify).with('Object#<<', nil).and_return('') resolve_links("{Object#<<}") end it "should warn about missing reference at right file location for object" do YARD.parse_string <<-eof # Comments here # And a reference to {InvalidObject} class MyObject; end eof logger = mock(:log) logger.should_receive(:warn).ordered.with("In file `(stdin)':2: Cannot resolve link to InvalidObject from text:") logger.should_receive(:warn).ordered.with("...{InvalidObject}") stub!(:log).and_return(logger) stub!(:object).and_return(Registry.at('MyObject')) resolve_links(object.docstring) end it "should show ellipsis on either side if there is more on the line in a reference warning" do YARD.parse_string <<-eof # {InvalidObject1} beginning of line # end of line {InvalidObject2} # Middle of {InvalidObject3} line # {InvalidObject4} class MyObject; end eof logger = mock(:log) logger.should_receive(:warn).ordered.with("In file `(stdin)':1: Cannot resolve link to InvalidObject1 from text:") logger.should_receive(:warn).ordered.with("{InvalidObject1}...") logger.should_receive(:warn).ordered.with("In file `(stdin)':2: Cannot resolve link to InvalidObject2 from text:") logger.should_receive(:warn).ordered.with("...{InvalidObject2}") logger.should_receive(:warn).ordered.with("In file `(stdin)':3: Cannot resolve link to InvalidObject3 from text:") logger.should_receive(:warn).ordered.with("...{InvalidObject3}...") logger.should_receive(:warn).ordered.with("In file `(stdin)':4: Cannot resolve link to InvalidObject4 from text:") logger.should_receive(:warn).ordered.with("{InvalidObject4}") stub!(:log).and_return(logger) stub!(:object).and_return(Registry.at('MyObject')) resolve_links(object.docstring) end it "should warn about missing reference for file template (no object)" do @file = CodeObjects::ExtraFileObject.new('myfile.txt', '') logger = mock(:log) logger.should_receive(:warn).ordered.with("In file `myfile.txt':3: Cannot resolve link to InvalidObject from text:") logger.should_receive(:warn).ordered.with("...{InvalidObject Some Title}") stub!(:log).and_return(logger) stub!(:object).and_return(Registry.root) resolve_links(<<-eof) Hello world This is a line And {InvalidObject Some Title} And more. eof end end describe '#signature' do before do @results = { :regular => "- (Object) foo", :default_return => "- (Hello) foo", :no_default_return => "- foo", :private_class => "+ (Object) foo (private)", :single => "- (String) foo", :two_types => "- (String, Symbol) foo", :two_types_multitag => "- (String, Symbol) foo", :type_nil => "- (Type?) foo", :type_array => "- (Type+) foo", :multitype => "- (Type, ...) foo", :void => "- (void) foo", :hide_void => "- foo", :block => "- (Object) foo {|a, b, c| ... }", :empty_overload => '- (String) foobar' } end def format_types(types, brackets = false) types.join(", ") end def signature(obj, link = false) super(obj, link).strip end it_should_behave_like "signature" it "should link to regular method if overload name does not have the same method name" do YARD.parse_string <<-eof class Foo # @overload bar(a, b, c) def foo; end end eof serializer = mock(:serializer) serializer.stub!(:serialized_path).with(Registry.at('Foo')).and_return('') stub!(:serializer).and_return(serializer) stub!(:object).and_return(Registry.at('Foo')) signature(Registry.at('Foo#foo').tag(:overload), true).should == "- bar(a, b, c) " end end describe '#html_syntax_highlight' do subject do obj = OpenStruct.new obj.options = options obj.object = Registry.root obj.extend(Templates::Helpers::HtmlHelper) obj end it "should return empty string on nil input" do subject.html_syntax_highlight(nil).should == '' end it "should call #html_syntax_highlight_ruby by default" do Registry.root.source_type = nil subject.should_receive(:html_syntax_highlight_ruby).with('def x; end') subject.html_syntax_highlight('def x; end') end it "should call #html_syntax_highlight_NAME if there's an object with a #source_type" do subject.object = OpenStruct.new(:source_type => :NAME) subject.should_receive(:respond_to?).with('html_markup_html').and_return(true) subject.should_receive(:respond_to?).with('html_syntax_highlight_NAME').and_return(true) subject.should_receive(:html_syntax_highlight_NAME).and_return("foobar") subject.htmlify('
            def x; end
            ', :html).should == '
            foobar
            ' end it "should add !!!LANG to className in outputted pre tag" do subject.object = OpenStruct.new(:source_type => :LANG) subject.should_receive(:respond_to?).with('html_markup_html').and_return(true) subject.should_receive(:respond_to?).with('html_syntax_highlight_LANG').and_return(true) subject.should_receive(:html_syntax_highlight_LANG).and_return("foobar") subject.htmlify("
            !!!LANG\ndef x; end
            ", :html).should == '
            foobar
            ' end it "should call html_syntax_highlight_NAME if source starts with !!!NAME" do subject.should_receive(:respond_to?).with('html_syntax_highlight_NAME').and_return(true) subject.should_receive(:html_syntax_highlight_NAME).and_return("foobar") subject.html_syntax_highlight(<<-eof !!!NAME def x; end eof ).should == "foobar" end it "should not highlight if highlight option is false" do subject.options.highlight = false subject.should_not_receive(:html_syntax_highlight_ruby) subject.html_syntax_highlight('def x; end').should == 'def x; end' end it "should not highlight if there is no highlight method specified by !!!NAME" do subject.should_receive(:respond_to?).with('html_syntax_highlight_NAME').and_return(false) subject.should_not_receive(:html_syntax_highlight_NAME) subject.html_syntax_highlight("!!!NAME\ndef x; end").should == "def x; end" end it "should highlight as ruby if htmlify(text, :ruby) is called" do subject.should_receive(:html_syntax_highlight_ruby).with('def x; end').and_return('x') subject.htmlify('def x; end', :ruby).should == '
            x
            ' end it "should not prioritize object source type when called directly" do subject.should_receive(:html_syntax_highlight_ruby).with('def x; end').and_return('x') subject.object = OpenStruct.new(:source_type => :c) subject.html_syntax_highlight("def x; end").should == "x" end it "shouldn't escape code snippets twice" do subject.htmlify('
            {"foo" => 1}
            ', :html).should == '
            {"foo" => 1}
            ' end it "should highlight source when matching a pre lang= tag" do subject.htmlify('
            x = 1
            ', :html).should == '
            x = 1
            ' end it "should highlight source when matching a code class= tag" do subject.htmlify('
            x = 1
            ', :html).should == '
            x = 1
            ' end end describe '#link_url' do it "should add target if scheme is provided" do link_url("http://url.com").should include(" target=\"_parent\"") link_url("https://url.com").should include(" target=\"_parent\"") link_url("irc://url.com").should include(" target=\"_parent\"") link_url("../not/scheme").should_not include("target") end end end yard-0.8.7.3/spec/templates/helpers/base_helper_spec.rb0000644000004100000410000001345012261240652023063 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::Templates::Helpers::BaseHelper do include YARD::Templates::Helpers::BaseHelper describe '#run_verifier' do it "should run verifier proc against list if provided" do mock = Verifier.new mock.should_receive(:call).with(1) mock.should_receive(:call).with(2) mock.should_receive(:call).with(3) should_receive(:options).at_least(1).times.and_return(Options.new.update(:verifier => mock)) run_verifier [1, 2, 3] end it "should prune list if lambda returns false and only false" do mock = Verifier.new should_receive(:options).at_least(1).times.and_return(Options.new.update(:verifier => mock)) mock.should_receive(:call).with(1).and_return(false) mock.should_receive(:call).with(2).and_return(true) mock.should_receive(:call).with(3).and_return(nil) mock.should_receive(:call).with(4).and_return("value") run_verifier([1, 2, 3, 4]).should == [2, 3, 4] end it "should return list if no verifier exists" do should_receive(:options).at_least(1).times.and_return(Options.new) run_verifier([1, 2, 3]).should == [1, 2, 3] end end describe '#h' do it "should return just the text" do h("hello world").should == "hello world" h(nil).should == nil end end describe '#link_object' do it "should return the title if provided" do link_object(1, "title").should == "title" link_object(Registry.root, "title").should == "title" end it "should return a path if argument is a Proxy or object" do link_object(Registry.root).should == "Top Level Namespace" link_object(P("Array")).should == "Array" end it "should should return path of Proxified object if argument is a String or Symbol" do link_object("Array").should == "Array" link_object(:"A::B").should == "A::B" end it "should return the argument if not an object, proxy, String or Symbol" do link_object(1).should == 1 end end describe '#link_url' do it "should return the URL" do link_url("http://url").should == "http://url" end end describe '#linkify' do before do stub!(:object).and_return(Registry.root) end it "should call #link_url for mailto: links" do should_receive(:link_url) linkify("mailto:steve@example.com") end it "should call #link_url for URL schemes (http://)" do should_receive(:link_url) linkify("http://example.com") end it "should call #link_file for file: links" do should_receive(:link_file).with('Filename', nil, 'anchor') linkify("file:Filename#anchor") end it "should pass off to #link_object if argument is an object" do obj = CodeObjects::NamespaceObject.new(nil, :YARD) should_receive(:link_object).with(obj) linkify obj end it "should return empty string and warn if object does not exist" do log.should_receive(:warn).with(/Cannot find object .* for inclusion/) linkify('include:NotExist').should == '' end it "should pass off to #link_url if argument is recognized as a URL" do url = "http://yardoc.org/" should_receive(:link_url).with(url, nil, {:target => '_parent'}) linkify url end it "should call #link_include_object for include:ObjectName" do obj = CodeObjects::NamespaceObject.new(:root, :Foo) should_receive(:link_include_object).with(obj) linkify 'include:Foo' end it "should call #link_include_file for include:file:path/to/file" do File.should_receive(:file?).with('path/to/file').and_return(true) File.should_receive(:read).with('path/to/file').and_return('FOO') linkify('include:file:path/to/file').should == 'FOO' end it "should not allow include:file for path above pwd" do log.should_receive(:warn).with("Cannot include file from path `a/b/../../../../file'") linkify('include:file:a/b/../../../../file').should == '' end it "should warn if include:file:path does not exist" do log.should_receive(:warn).with(/Cannot find file .+ for inclusion/) linkify('include:file:notexist').should == '' end end describe '#format_types' do it "should return the list of types separated by commas surrounded by brackets" do format_types(['a', 'b', 'c']).should == '(a, b, c)' end it "should return the list of types without brackets if brackets=false" do format_types(['a', 'b', 'c'], false).should == 'a, b, c' end it "should should return an empty string if list is empty or nil" do format_types(nil).should == "" format_types([]).should == "" end end describe '#format_object_type' do it "should return Exception if type is Exception" do obj = mock(:object) obj.stub!(:is_a?).with(YARD::CodeObjects::ClassObject).and_return(true) obj.stub!(:is_exception?).and_return(true) format_object_type(obj).should == "Exception" end it "should return Class if type is Class" do obj = mock(:object) obj.stub!(:is_a?).with(YARD::CodeObjects::ClassObject).and_return(true) obj.stub!(:is_exception?).and_return(false) format_object_type(obj).should == "Class" end it "should return object type in other cases" do obj = mock(:object) obj.stub!(:type).and_return("value") format_object_type(obj).should == "Value" end end describe '#format_object_title' do it "should return Top Level Namespace for root object" do format_object_title(Registry.root).should == "Top Level Namespace" end it "should return 'type: title' in other cases" do obj = mock(:object) obj.stub!(:type).and_return(:class) obj.stub!(:title).and_return("A::B::C") format_object_title(obj).should == "Class: A::B::C" end end end yard-0.8.7.3/spec/templates/helpers/html_syntax_highlight_helper_spec.rb0000644000004100000410000000503112261240652026546 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::Templates::Helpers::HtmlSyntaxHighlightHelper do include YARD::Templates::Helpers::HtmlHelper include YARD::Templates::Helpers::HtmlSyntaxHighlightHelper describe '#html_syntax_highlight' do before do stub!(:object).and_return Registry.root Registry.root.source_type = :ruby end it "should not highlight source if options.highlight is false" do should_receive(:options).and_return(Options.new.update(:highlight => false)) html_syntax_highlight("def x\nend").should == "def x\nend" end it "should highlight source (legacy)" do type = Parser::SourceParser.parser_type Parser::SourceParser.parser_type = :ruby18 should_receive(:options).and_return(Options.new.update(:highlight => true)) expect = "defx 'x'+ /x/iend" result = html_syntax_highlight("def x\n 'x' + /x/i\nend") html_equals_string(result, expect) Parser::SourceParser.parser_type = type end it "should highlight source (ripper)" do should_receive(:options).and_return(Options.new.update(:highlight => true)) Parser::SourceParser.parser_type = :ruby expect = "def x ' x' + /x /i\nend" result = html_syntax_highlight("def x\n 'x' + /x/i\nend") html_equals_string(result, expect) end if HAVE_RIPPER it "should return escaped unhighlighted source if a syntax error is found (ripper)" do should_receive(:options).and_return(Options.new.update(:highlight => true)) html_syntax_highlight("def &x; ... end").should == "def &x; ... end" end if HAVE_RIPPER it "should return escaped unhighlighted source if a syntax error is found (ripper)" do should_receive(:options).and_return(Options.new.update(:highlight => true)) html_syntax_highlight("$ git clone http://url").should == "$ git clone http://url" end if HAVE_RIPPER end endyard-0.8.7.3/spec/templates/helpers/text_helper_spec.rb0000644000004100000410000000275212261240652023140 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../../spec_helper' require File.dirname(__FILE__) + "/shared_signature_examples" describe YARD::Templates::Helpers::TextHelper do include YARD::Templates::Helpers::TextHelper include YARD::Templates::Helpers::MethodHelper describe '#signature' do before do @results = { :regular => "root.foo -> Object", :default_return => "root.foo -> Hello", :no_default_return => "root.foo", :private_class => "A.foo -> Object (private)", :single => "root.foo -> String", :two_types => "root.foo -> (String, Symbol)", :two_types_multitag => "root.foo -> (String, Symbol)", :type_nil => "root.foo -> Type?", :type_array => "root.foo -> Type+", :multitype => "root.foo -> (Type, ...)", :void => "root.foo -> void", :hide_void => "root.foo", :block => "root.foo {|a, b, c| ... } -> Object", :empty_overload => 'root.foobar -> String' } end def signature(obj) super(obj).strip end it_should_behave_like "signature" end describe '#align_right' do it "should align text right" do text = "Method: #some_method (SomeClass)" align_right(text).should == ' ' * 40 + text end it "should truncate text that is longer than allowed width" do text = "(Defined in: /home/user/.rip/.packages/some_gem-2460672e333ac07b9190ade88ec9a91c/long/path.rb)" align_right(text).should == ' ' + text[0,68] + '...' end end endyard-0.8.7.3/spec/templates/template_spec.rb0000644000004100000410000003201312261240652020757 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::Templates::Template do def template(path) YARD::Templates::Engine.template!(path, '/full/path/' + path.to_s) end before :each do YARD::Templates::ErbCache.clear! end describe '.include_parent' do it "should not include parent directory if parent directory is a template root path" do mod = template('q') mod.should_not include(template('')) end it "should include overridden parent directory" do Engine.stub!(:template_paths).and_return(['/foo', '/bar']) File.should_receive(:directory?).with('/foo/a/b').and_return(true) File.should_receive(:directory?).with('/bar/a/b').and_return(false) File.should_receive(:directory?).with('/foo/a').at_least(1).times.and_return(true) File.should_receive(:directory?).with('/bar/a').at_least(1).times.and_return(true) ancestors = Engine.template('a/b').ancestors.map {|c| c.class_name } ancestors[0, 3].should == %w( Template__foo_a_b Template__bar_a Template__foo_a ) end it "should include parent directory template if exists" do mod1 = template('x') mod2 = template('x/y') mod2.should include(mod1) end end describe '.full_paths' do it "should list full_path" do mod = template(:a) mod.full_paths.should == ['/full/path/a'] end it "should list paths of included modules" do mod = template(:a) mod.send(:include, template(:b)) mod.full_paths.should == ['/full/path/a', '/full/path/b'] end it "should list paths from modules of included modules" do mod = template(:c) mod.send(:include, template(:d)) mod.send(:include, template(:a)) mod.full_paths.should == ['c', 'a', 'b', 'd'].map {|o| '/full/path/' + o } end it "should only list full paths of modules that respond to full_paths" do mod = template(:d) mod.send(:include, Enumerable) mod.full_paths.should == ['/full/path/d'] end end describe '.load_setup_rb' do it "should load setup.rb file for module" do File.should_receive(:file?).with('/full/path/e/setup.rb').and_return(true) File.should_receive(:read).with('/full/path/e/setup.rb').and_return('def success; end') template(:e).new.should respond_to(:success) end end describe '.T' do it "should load template from absolute path" do mod = template(:a) Engine.should_receive(:template).with('other') mod.T('other') end end describe '.find_file' do it "should find file in module's full_path" do File.should_receive(:file?).with('/full/path/a/basename').and_return(false) File.should_receive(:file?).with('/full/path/b/basename').and_return(true) template(:a).find_file('basename').should == '/full/path/b/basename' end it "should return nil if no file is found" do File.should_receive(:file?).with('/full/path/a/basename').and_return(false) File.should_receive(:file?).with('/full/path/b/basename').and_return(false) template(:a).find_file('basename').should be_nil end end describe '.find_nth_file' do it "should find 2nd existing file in template paths" do File.should_receive(:file?).with('/full/path/a/basename').and_return(true) File.should_receive(:file?).with('/full/path/b/basename').and_return(true) template(:a).find_nth_file('basename', 2).should == '/full/path/b/basename' end it "should return nil if no file is found" do File.should_receive(:file?).with('/full/path/a/basename').and_return(true) File.should_receive(:file?).with('/full/path/b/basename').and_return(true) template(:a).find_nth_file('basename', 3).should be_nil end end describe '.extra_includes' do it "should be included when a module is initialized" do module MyModule; end Template.extra_includes << MyModule template(:e).new.should be_kind_of(MyModule) end it "should support lambdas in list" do module MyModule2; end Template.extra_includes << lambda {|opts| MyModule2 if opts.format == :html } template(:f).new(:format => :html).should be_kind_of(MyModule2) metaclass = (class << template(:g).new(:format => :text); self end) metaclass.ancestors.should_not include(MyModule2) end end describe '.is_a?' do it "should be kind of Template" do template(:e).is_a?(Template).should == true end end describe '#T' do it "should delegate to class method" do template(:e).should_receive(:T).with('test') template(:e).new.T('test') end end describe '#init' do it "should be called during initialization" do module YARD::Templates::Engine::Template__full_path_e def init; sections 1, 2, 3 end end template(:e).new.sections.should == Section.new(nil, 1, 2, 3) end end describe '#file' do it "should read the file if it exists" do File.should_receive(:file?).with('/full/path/e/abc').and_return(true) IO.should_receive(:read).with('/full/path/e/abc').and_return('hello world') template(:e).new.file('abc').should == 'hello world' end it "should raise ArgumentError if the file does not exist" do File.should_receive(:file?).with('/full/path/e/abc').and_return(false) lambda { template(:e).new.file('abc') }.should raise_error(ArgumentError) end it "should replace {{{__super__}}} with inherited template contents if allow_inherited=true" do File.should_receive(:file?).with('/full/path/a/abc').twice.and_return(true) File.should_receive(:file?).with('/full/path/b/abc').and_return(true) IO.should_receive(:read).with('/full/path/a/abc').and_return('foo {{{__super__}}}') IO.should_receive(:read).with('/full/path/b/abc').and_return('bar') template(:a).new.file('abc', true).should == "foo bar" end it "should not replace {{{__super__}}} with inherited template contents if allow_inherited=false" do File.should_receive(:file?).with('/full/path/a/abc').and_return(true) IO.should_receive(:read).with('/full/path/a/abc').and_return('foo {{{__super__}}}') template(:a).new.file('abc').should == "foo {{{__super__}}}" end end describe '#superb' do it "should return the inherited erb template contents" do File.should_receive(:file?).with('/full/path/a/test.erb').and_return(true) File.should_receive(:file?).with('/full/path/b/test.erb').and_return(true) IO.should_receive(:read).with('/full/path/b/test.erb').and_return('bar') template = template(:a).new template.section = :test template.superb.should == "bar" end it "should work inside an erb template" do File.should_receive(:file?).with('/full/path/a/test.erb').twice.and_return(true) File.should_receive(:file?).with('/full/path/b/test.erb').and_return(true) IO.should_receive(:read).with('/full/path/a/test.erb').and_return('foo<%= superb %>!') IO.should_receive(:read).with('/full/path/b/test.erb').and_return('bar') template = template(:a).new template.section = :test template.erb(:test).should == "foobar!" end end describe '#sections' do it "should allow sections to be set if arguments are provided" do mod = template(:e).new mod.sections 1, 2, [3] mod.sections.should == Section.new(nil, 1, 2, [3]) end end describe '#run' do it "should render all sections" do mod = template(:e).new mod.should_receive(:render_section).with(Section.new(:a)).and_return('a') mod.should_receive(:render_section).with(Section.new(:b)).and_return('b') mod.should_receive(:render_section).with(Section.new(:c)).and_return('c') mod.sections :a, :b, :c mod.run.should == 'abc' end it "should render all sections with options" do mod = template(:e).new mod.should_receive(:render_section).with(Section.new(:a)).and_return('a') mod.should_receive(:add_options).with(:a => 1).and_yield mod.sections :a mod.run(:a => 1).should == 'a' end it "should run section list if provided" do mod = template(:e).new mod.should_receive(:render_section).with(Section.new(:q)) mod.should_receive(:render_section).with(Section.new(:x)) mod.run({}, [:q, :x]) end it "should accept a nil section as empty string" do mod = template(:e).new mod.should_receive(:render_section).with(Section.new(:a)) mod.sections :a mod.run.should == "" end end describe '#add_options' do it "should set instance variables in addition to options" do mod = template(:f).new mod.send(:add_options, {:a => 1, :b => 2}) mod.options.should == {:a => 1, :b => 2} mod.instance_variable_get("@a").should == 1 mod.instance_variable_get("@b").should == 2 end it "should set instance variables and options only for the block" do mod = template(:f).new mod.send(:add_options, {:a => 100, :b => 200}) do mod.options.should == {:a => 100, :b => 200} end mod.options.should_not == {:a => 100, :b => 200} end end describe '#render_section' do it "should call method if method exists by section name as Symbol" do mod = template(:f).new mod.should_receive(:respond_to?).with(:a).and_return(true) mod.should_receive(:respond_to?).with('a').and_return(true) mod.should_receive(:send).with(:a).and_return('a') mod.should_receive(:send).with('a').and_return('a') mod.run({}, [:a, 'a']).should == 'aa' end it "should call erb if no method exists by section name" do mod = template(:f).new mod.should_receive(:respond_to?).with(:a).and_return(false) mod.should_receive(:respond_to?).with('a').and_return(false) mod.should_receive(:erb).with(:a).and_return('a') mod.should_receive(:erb).with('a').and_return('a') mod.run({}, [:a, 'a']).should == 'aa' end it "should run a template if section is one" do mod2 = template(:g) mod2.should_receive(:run) mod = template(:f).new mod.sections mod2 mod.run end it "should run a template instance if section is one" do mod2 = template(:g).new mod2.should_receive(:run) mod = template(:f).new mod.sections mod2 mod.run end end describe '#yield' do it "should yield a subsection" do mod = template(:e).new mod.sections :a, [:b, :c] class << mod def a; "(" + yield + ")" end def b; "b" end def c; "c" end end mod.run.should == "(b)" end it "should yield a subsection within a yielded subsection" do mod = template(:e).new mod.sections :a, [:b, [:c]] class << mod def a; "(" + yield + ")" end def b; yield end def c; "c" end end mod.run.should == "(c)" end it "should support arbitrary nesting" do mod = template(:e).new mod.sections :a, [:b, [:c, [:d, [:e]]]] class << mod def a; "(" + yield + ")" end def b; yield end def c; yield end def d; yield end def e; "e" end end mod.run.should == "(e)" end it "should yield first two elements if yield is called twice" do mod = template(:e).new mod.sections :a, [:b, :c, :d] class << mod def a; "(" + yield + yield + ")" end def b; 'b' end def c; "c" end end mod.run.should == "(bc)" end it "should ignore any subsections inside subsection yields" do mod = template(:e).new mod.sections :a, [:b, [:c], :d] class << mod def a; "(" + yield + yield + ")" end def b; 'b' end def d; "d" end end mod.run.should == "(bd)" end it "should allow extra options passed via yield" do mod = template(:e).new mod.sections :a, [:b] class << mod def a; "(" + yield(:x => "a") + ")" end def b; options.x + @x end end mod.run.should == "(aa)" end end describe '#yieldall' do it "should yield all subsections" do mod = template(:e).new mod.sections :a, [:b, [:d, [:e]], :c] class << mod def a; "(" + yieldall + ")" end def b; "b" + yieldall end def c; "c" end def d; 'd' + yieldall end def e; 'e' end end mod.run.should == "(bdec)" end it "should yield options to all subsections" do mod = template(:e).new mod.sections :a, [:b, :c] class << mod def a; "(" + yieldall(:x => "2") + ")" end def b; @x end def c; @x end end mod.run.should == "(22)" end it "should yield all subsections more than once" do mod = template(:e).new mod.sections :a, [:b] class << mod def a; "(" + yieldall + yieldall + ")" end def b; "b" end end mod.run.should == "(bb)" end it "should not yield if no yieldall is called" do mod = template(:e).new mod.sections :a, [:b] class << mod def a; "()" end def b; "b" end end mod.run.should == "()" end end end yard-0.8.7.3/spec/templates/engine_spec.rb0000644000004100000410000001101312261240652020406 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::Templates::Engine do describe '.register_template_path' do it "should register a String path" do Engine.register_template_path('.') Engine.template_paths.pop.should == '.' end end describe '.template!' do it "should create a module including Template" do mod = Engine.template!('path/to/template') mod.should include(Template) mod.full_path.to_s.should == 'path/to/template' end it "should create a module including Template with full_path" do mod = Engine.template!('path/to/template2', '/full/path/to/template2') mod.should include(Template) mod.full_path.to_s.should == '/full/path/to/template2' end end describe '.template' do it "should raise an error if the template is not found" do lambda { Engine.template(:a, :b, :c) }.should raise_error(ArgumentError) end it "should create a module including Template" do mock = mock(:template) Engine.should_receive(:find_template_paths).with(nil, 'template/name').and_return(['/full/path/template/name']) Engine.should_receive(:template!).with('template/name', ['/full/path/template/name']).and_return(mock) Engine.template('template/name').should == mock end it "should create a Template from a relative Template path" do Engine.should_receive(:template_paths).and_return([]) File.should_receive(:directory?).with("/full/path/template/notname").and_return(true) start_template = mock(:start_template) start_template.stub!(:full_path).and_return('/full/path/template/name') start_template.stub!(:full_paths).and_return(['/full/path/template/name']) start_template.should_receive(:is_a?).with(Template).and_return(true) mod = Engine.template(start_template, '..', 'notname') mod.should include(Template) mod.full_path.to_s.should == "/full/path/template/notname" end it "should create a Template including other matching templates in path" do paths = ['/full/path/template/name', '/full/path2/template/name'] Engine.should_receive(:find_template_paths).with(nil, 'template').at_least(1).times.and_return([]) Engine.should_receive(:find_template_paths).with(nil, 'template/name').and_return(paths) ancestors = Engine.template('template/name').ancestors.map {|m| m.class_name } ancestors.should include("Template__full_path2_template_name") end it "should include parent directories before other template paths" do paths = ['/full/path/template/name', '/full/path2/template/name'] Engine.should_receive(:find_template_paths).with(nil, 'template/name').and_return(paths) ancestors = Engine.template('template/name').ancestors.map {|m| m.class_name } ancestors[0, 4].should == ["Template__full_path_template_name", "Template__full_path_template", "Template__full_path2_template_name", "Template__full_path2_template"] end end describe '.generate' do it "should generate with fulldoc template" do mod = mock(:template) options = TemplateOptions.new options.reset_defaults options.objects = [:a, :b, :c] options.object = Registry.root mod.should_receive(:run).with(options) Engine.should_receive(:template).with(:default, :fulldoc, :text).and_return(mod) Engine.generate([:a, :b, :c]) end end describe '.render' do def loads_template(*args) Engine.should_receive(:template).with(*args).and_return(@template) end before(:all) do @object = CodeObjects::MethodObject.new(:root, :method) end before do @options = TemplateOptions.new @options.reset_defaults @options.object = @object @options.type = @object.type @template = mock(:template) @template.stub!(:include) @template.should_receive(:run).with(@options) end it "should accept method call with no parameters" do loads_template(:default, :method, :text) @object.format end it "should allow template key to be changed" do loads_template(:javadoc, :method, :text) @options.template = :javadoc @object.format(:template => :javadoc) end it "should allow type key to be changed" do loads_template(:default, :fulldoc, :text) @options.type = :fulldoc @object.format(:type => :fulldoc) end it "should allow format key to be changed" do loads_template(:default, :method, :html) @options.format = :html @object.format(:format => :html) end end end yard-0.8.7.3/spec/templates/tag_spec.rb0000644000004100000410000000263612261240652017727 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::Templates::Engine.template(:default, :tags) do before { Registry.clear } describe 'all known tags' do before do YARD.parse_string <<-'eof' # Comments # @abstract override me # @param [Hash] opts the options # @option opts :key ('') hello # @option opts :key2 (X) hello # @return [String] the result # @raise [Exception] Exception class # @deprecated for great justice # @see A # @see http://url.com # @see http://url.com Example # @author Name # @since 1.0 # @version 1.0 # @yield a block # @yieldparam [String] a a value # @yieldreturn [Hash] a hash # @example Wash your car # car.wash # @example To kill a mockingbird # a = String.new # flip(a.reverse) def m(opts = {}) end eof end it "should render text format correctly" do text_equals(Registry.at('#m').format(text_options), :tag001) end end describe 'param tags on non-methods' do it 'should not display @param tags on non-method objects' do YARD.parse_string <<-'eof' # @param [#to_s] name the name module Foo; end eof proc = lambda { Registry.at('Foo').format(html_options) } proc.should_not raise_error(NoMethodError) end end endyard-0.8.7.3/spec/rubygems/0000755000004100000410000000000012261240652015445 5ustar www-datawww-datayard-0.8.7.3/spec/rubygems/doc_manager_spec.rb0000644000004100000410000000723212261240652021247 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' require File.join(YARD::ROOT, 'rubygems_plugin') require 'fileutils' describe Gem::DocManager do before do # Ensure filesystem integrity FileUtils.stub(:mkdir_p) FileUtils.stub(:rm_rf) Dir.stub(:chdir) YARD::CLI::Yardoc.stub(:run) @spec_file = File.join(YARD::ROOT, '..', 'yard.gemspec') @spec = Gem::SourceIndex.load_specification(@spec_file) @spec.has_yardoc = false # no yardoc docs for now @yardopts = File.join(@spec.full_gem_path, '.yardopts') @doc = Gem::DocManager.new(@spec) @doc.stub(:install_ri_yard_orig) @doc.stub(:install_rdoc_yard_orig) end def runs; YARD::CLI::Yardoc.should_receive(:run) end describe '.load_yardoc' do it "should properly load YARD" do Gem::DocManager.should_receive(:require) do |path| File.expand_path(path).should == YARD::ROOT + '/yard' end Gem::DocManager.load_yardoc end end describe '#install_ri_yard' do def install msg = "Building YARD (yri) index for #{@spec.full_name}..." @doc.should_receive(:say).with(msg) @doc.install_ri_yard end it "should pass --quiet to all documentation" do runs.with('-c', '-n', '--quiet', 'lib') install end it "should pass extra_rdoc_files to documentation" do @spec.extra_rdoc_files = %w(README LICENSE) runs.with('-c', '-n', '--quiet', 'lib', '-', 'README', 'LICENSE') install end it "should add --backtrace if Gem.configuration.backtrace" do Gem.configuration.backtrace = true runs.with('-c', '-n', '--quiet', '--backtrace', 'lib') install Gem.configuration.backtrace = false end it "should add require_paths if there is no .yardopts" do File.should_receive(:file?).with(@yardopts).and_return(true) runs.with('-c', '-n', '--quiet') install end it "should add extra_rdoc_files if there is no .yardopts" do @spec.extra_rdoc_files = %w(README LICENSE) File.should_receive(:file?).with(@yardopts).and_return(true) runs.with('-c', '-n', '--quiet') install end it "should switch to directory before running command" do old = Dir.pwd Dir.should_receive(:chdir).with(@spec.full_gem_path) Dir.should_receive(:chdir).with(old) install end it "should ensure that directory is switched back at end of command in failure" do old = Dir.pwd Dir.should_receive(:chdir).with(@spec.full_gem_path) Dir.should_receive(:chdir).with(old) @doc.ui.errs.should_receive(:puts).with(/ERROR:\s*While generating documentation/) @doc.ui.errs.should_receive(:puts).with(/MESSAGE:\s*foo/) @doc.ui.errs.should_receive(:puts).with(/YARDOC args:\s*-c -n --quiet lib/) @doc.ui.errs.should_receive(:puts).with("(continuing with the rest of the installation)") YARD::CLI::Yardoc.should_receive(:run).and_raise(RuntimeError.new("foo")) install end it "should handle permission errors" do YARD::CLI::Yardoc.should_receive(:run).and_raise(Errno::EACCES.new("- dir")) lambda { install }.should raise_error(Gem::FilePermissionError) end end describe '#install_rdoc_yard' do def install msg = "Installing YARD documentation for #{@spec.full_name}..." @doc.should_receive(:say).with(msg) @doc.install_rdoc_yard end it "should add -o outdir when generating docs" do File.should_receive(:file?).with(@yardopts).and_return(true) @spec.has_yardoc = true doc_dir = File.join(@doc.instance_variable_get("@doc_dir"), 'rdoc') runs.with('-o', doc_dir, '--quiet') install end end end if Gem::VERSION < '2.0.0' yard-0.8.7.3/spec/rake/0000755000004100000410000000000012261240652014532 5ustar www-datawww-datayard-0.8.7.3/spec/rake/yardoc_task_spec.rb0000644000004100000410000000507012261240652020376 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::Rake::YardocTask do before do @yardoc = YARD::CLI::Yardoc.new @yardoc.statistics = false @yardoc.use_document_file = false @yardoc.use_yardopts_file = false @yardoc.generate = false Templates::Engine.stub!(:render) Templates::Engine.stub!(:generate) YARD.stub!(:parse) Registry.stub!(:load) Registry.stub!(:save) YARD::CLI::Yardoc.stub!(:new).and_return(@yardoc) ::Rake.application.clear end def run ::Rake.application.tasks[0].invoke end describe '#initialize' do it "should allow separate rake task name to be set" do YARD::Rake::YardocTask.new(:notyardoc) ::Rake.application.tasks[0].name.should == "notyardoc" end end describe '#files' do it "should allow files to be set" do YARD::Rake::YardocTask.new do |t| t.files = ['a', 'b', 'c'] end run @yardoc.files.should == %w(a b c) end end describe '#options' do it "should allow extra options to be set" do YARD::Rake::YardocTask.new do |t| t.options = ['--private', '--protected'] end run @yardoc.visibilities.should == [:public, :private, :protected] end it "should allow --api and --no-api" do YARD::Rake::YardocTask.new do |t| t.options = %w(--api public --no-api) end run @yardoc.options.verifier.expressions. should include('["public"].include?(@api.text) || !@api') end end describe '#before' do it "should allow before callback" do proc = lambda { } proc.should_receive(:call) @yardoc.should_receive(:run) YARD::Rake::YardocTask.new {|t| t.before = proc } run end end describe '#after' do it "should allow after callback" do proc = lambda { } proc.should_receive(:call) @yardoc.should_receive(:run) YARD::Rake::YardocTask.new {|t| t.after = proc } run end end describe '#verifier' do it "should allow a verifier proc to be set" do verifier = Verifier.new @yardoc.should_receive(:run) do @yardoc.options[:verifier].should == verifier end YARD::Rake::YardocTask.new {|t| t.verifier = verifier } run end it "should override --query options" do verifier = Verifier.new @yardoc.should_receive(:run) do @yardoc.options[:verifier].should == verifier end YARD::Rake::YardocTask.new do |t| t.options += ['--query', '@return'] t.verifier = verifier end run end end end yard-0.8.7.3/spec/docstring_spec.rb0000644000004100000410000002544012261240652017150 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::Docstring do before { YARD::Registry.clear } describe '#initialize' do it "should handle docstrings with empty newlines" do Docstring.new("\n\n").should == "" end end describe '#+' do it "should add another Docstring" do d = Docstring.new("FOO") + Docstring.new("BAR") d.should == "FOO\nBAR" end it "should copy over tags" do d1 = Docstring.new("FOO\n@api private\n") d2 = Docstring.new("BAR\n@param foo descr") d = (d1 + d2) d.should have_tag(:api) d.should have_tag(:param) end it "should add a String" do d = Docstring.new("FOO") + "BAR" d.should == "FOOBAR" end end describe '#line' do it "should return nil if #line_range is not set" do Docstring.new('foo').line.should be_nil end it "should return line_range.first if #line_range is set" do doc = Docstring.new('foo') doc.line_range = (1..10) doc.line.should == doc.line_range.first end end describe '#summary' do it "should handle empty docstrings" do o1 = Docstring.new o1.summary.should == "" end it "should handle multiple calls" do o1 = Docstring.new("Hello. world") 5.times { o1.summary.should == "Hello." } end it "should strip HTML before summarizing" do doc = Docstring.new("

            Hello world

            .") doc.summary.should == 'Hello world.' end it "should strip newlines in first paragraph before summarizing" do doc = Docstring.new("Foo\n== bar.") doc.summary.should == 'Foo == bar.' end it "should return the first sentence" do o = Docstring.new("DOCSTRING. Another sentence") o.summary.should == "DOCSTRING." end it "should return the first paragraph" do o = Docstring.new("DOCSTRING, and other stuff\n\nAnother sentence.") o.summary.should == "DOCSTRING, and other stuff." end it "should return proper summary when docstring is changed" do o = Docstring.new "DOCSTRING, and other stuff\n\nAnother sentence." o.summary.should == "DOCSTRING, and other stuff." o = Docstring.new "DOCSTRING." o.summary.should == "DOCSTRING." end it "should not double the ending period" do o = Docstring.new("Returns a list of tags specified by +name+ or all tags if +name+ is not specified.\n\nTest") o.summary.should == "Returns a list of tags specified by +name+ or all tags if +name+ is not specified." doc = Docstring.new(<<-eof) Returns a list of tags specified by +name+ or all tags if +name+ is not specified. @param name the tag name to return data for, or nil for all tags @return [Array] the list of tags by the specified tag name eof doc.summary.should == "Returns a list of tags specified by +name+ or all tags if +name+ is not specified." end it "should not attach period if entire summary is include" do YARD.parse_string "# docstring\ndef foo; end" Docstring.new("{include:#foo}").summary.should == '{include:#foo}' Registry.clear end it "should handle references embedded in summary" do Docstring.new("Aliasing {Test.test}. Done.").summary.should == "Aliasing {Test.test}." end it "should only end first sentence when outside parentheses" do Docstring.new("Hello (the best.) world. Foo bar.").summary.should == "Hello (the best.) world." Docstring.new("A[b.]c.").summary.should == "A[b.]c." end it "should only see '.' as period if whitespace (or eof) follows" do Docstring.new("hello 1.5 times.").summary.should == "hello 1.5 times." Docstring.new("hello... me").summary.should == "hello..." Docstring.new("hello.").summary.should == "hello." end end describe '#ref_tags' do it "should parse reference tag into ref_tags" do doc = Docstring.new("@return (see Foo#bar)") doc.ref_tags.size.should == 1 doc.ref_tags.first.owner.should == P("Foo#bar") doc.ref_tags.first.tag_name.should == "return" doc.ref_tags.first.name.should be_nil end it "should parse named reference tag into ref_tags" do doc = Docstring.new("@param blah \n (see Foo#bar )") doc.ref_tags.size.should == 1 doc.ref_tags.first.owner.should == P("Foo#bar") doc.ref_tags.first.tag_name.should == "param" doc.ref_tags.first.name.should == "blah" end it "should fail to parse named reference tag into ref_tags" do doc = Docstring.new("@param blah THIS_BREAKS_REFTAG (see Foo#bar)") doc.ref_tags.size.should == 0 end it "should return all valid reference tags along with #tags" do o = CodeObjects::MethodObject.new(:root, 'Foo#bar') o.docstring.add_tag Tags::Tag.new('return', 'testing') doc = Docstring.new("@return (see Foo#bar)") tags = doc.tags tags.size.should == 1 tags.first.text.should == 'testing' tags.first.should be_kind_of(Tags::RefTag) tags.first.owner.should == o end it "should return all valid named reference tags along with #tags(name)" do o = CodeObjects::MethodObject.new(:root, 'Foo#bar') o.docstring.add_tag Tags::Tag.new('param', 'testing', nil, '*args') o.docstring.add_tag Tags::Tag.new('param', 'NOTtesting', nil, 'notargs') doc = Docstring.new("@param *args (see Foo#bar)") tags = doc.tags('param') tags.size.should == 1 tags.first.text.should == 'testing' tags.first.should be_kind_of(Tags::RefTag) tags.first.owner.should == o end it "should ignore invalid reference tags" do doc = Docstring.new("@param *args (see INVALID::TAG#tag)") tags = doc.tags('param') tags.size.should == 0 end it "resolves references to methods in the same class with #methname" do klass = CodeObjects::ClassObject.new(:root, "Foo") o = CodeObjects::MethodObject.new(klass, "bar") ref = CodeObjects::MethodObject.new(klass, "baz") o.docstring.add_tag Tags::Tag.new('param', 'testing', nil, 'arg1') ref.docstring = "@param (see #bar)" tags = ref.docstring.tags("param") tags.size.should == 1 tags.first.text.should == "testing" tags.first.should be_kind_of(Tags::RefTag) tags.first.owner.should == o end end describe '#empty?/#blank?' do before(:all) do Tags::Library.define_tag "Invisible", :invisible_tag end it "should be blank and empty if it has no content and no tags" do Docstring.new.should be_blank Docstring.new.should be_empty end it "shouldn't be empty or blank if it has content" do d = Docstring.new("foo bar") d.should_not be_empty d.should_not be_blank end it "should be empty but not blank if it has tags" do d = Docstring.new("@param foo") d.should be_empty d.should_not be_blank end it "should be empty but not blank if it has ref tags" do o = CodeObjects::MethodObject.new(:root, 'Foo#bar') o.docstring.add_tag Tags::Tag.new('return', 'testing') d = Docstring.new("@return (see Foo#bar)") d.should be_empty d.should_not be_blank end it "should be blank if it has no visible tags" do d = Docstring.new("@invisible_tag value") d.should be_blank end it "should not be blank if it has invisible tags and only_visible_tags = false" do d = Docstring.new("@invisible_tag value") d.add_tag Tags::Tag.new('invisible_tag', nil, nil) d.blank?(false).should == false end end describe '#delete_tags' do it "should delete tags by a given tag name" do doc = Docstring.new("@param name x\n@param name2 y\n@return foo") doc.delete_tags(:param) doc.tags.size.should == 1 end end describe '#delete_tag_if' do it "should delete tags for a given block" do doc = Docstring.new("@param name x\n@param name2 y\n@return foo") doc.delete_tag_if {|t| t.name == 'name2' } doc.tags.size.should == 2 end end describe '#to_raw' do it "should return a clean representation of tags" do doc = Docstring.new("Hello world\n@return [String, X] foobar\n@param name the name\nBYE!") doc.to_raw.should == "Hello world\nBYE!\n@param [Array] name\n the name\n@return [String, X] foobar" end it "should handle tags with newlines and indentation" do doc = Docstring.new("@example TITLE\n the \n example\n @foo\n@param [X] name\n the name") doc.to_raw.should == "@example TITLE\n the \n example\n @foo\n@param [X] name\n the name" end it "should handle deleted tags" do doc = Docstring.new("@example TITLE\n the \n example\n @foo\n@param [X] name\n the name") doc.delete_tags(:param) doc.to_raw.should == "@example TITLE\n the \n example\n @foo" end it "should handle added tags" do doc = Docstring.new("@example TITLE\n the \n example\n @foo") doc.add_tag(Tags::Tag.new('foo', 'foo')) doc.to_raw.should == "@example TITLE\n the \n example\n @foo\n@foo foo" end it "should be equal to .all if not modified" do doc = Docstring.new("123\n@param") doc.to_raw.should == doc.all end # @bug gh-563 it "should handle full @option tags" do doc = Docstring.new("@option foo [String] bar (nil) baz") doc.to_raw.should == "@option foo [String] bar (nil) baz" end # @bug gh-563 it "should handle simple @option tags" do doc = Docstring.new("@option foo :key bar") doc.to_raw.should == "@option foo :key bar" end end describe '#dup' do it "should duplicate docstring text" do doc = Docstring.new("foo") doc.dup.should == doc doc.dup.all.should == doc end it "should duplicate tags to new list" do doc = Docstring.new("@param x\n@return y") doc2 = doc.dup doc2.delete_tags(:param) doc.tags.size.should == 2 doc2.tags.size.should == 1 end it "should preserve summary" do doc = Docstring.new("foo. bar") doc.dup.summary.should == doc.summary end it "should preserve hash_flag" do doc = Docstring.new doc.hash_flag = 'foo' doc.dup.hash_flag.should == doc.hash_flag end it "should preserve line_range" do doc = Docstring.new doc.line_range = (1..2) doc.dup.line_range.should == doc.line_range end end describe 'reference docstrings' do it 'allows for construction of docstring with ref object' do YARD.parse_string <<-eof class A # Docstring # @return [Boolean] def a; end # (see #a) def b; end end eof object = YARD::Registry.at('A#b') object.docstring.should == 'Docstring' object.tags.map {|x| x.tag_name }.should == ['return'] YARD::Registry.clear end end end yard-0.8.7.3/spec/options_spec.rb0000644000004100000410000001116112261240652016642 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::Options do class FooOptions < YARD::Options attr_accessor :foo def initialize; self.foo = "abc" end end describe '.default_attr' do it "should allow default attributes to be defined with symbols" do class DefaultOptions1 < YARD::Options default_attr :foo, 'HELLO' end o = DefaultOptions1.new o.reset_defaults o.foo.should == 'HELLO' end it "should call lambda if value is a Proc" do class DefaultOptions2 < YARD::Options default_attr :foo, lambda { 100 } end o = DefaultOptions2.new o.reset_defaults o.foo.should == 100 end end describe '#reset_defaults' do it "should not define defaults until reset is called" do class ResetDefaultOptions1 < YARD::Options default_attr :foo, 'FOO' end ResetDefaultOptions1.new.foo.should be_nil o = ResetDefaultOptions1.new o.reset_defaults o.foo.should == 'FOO' end it "should use defaults from superclass as well" do class ResetDefaultOptions2 < YARD::Options default_attr :foo, 'FOO' end class ResetDefaultOptions3 < ResetDefaultOptions2 end o = ResetDefaultOptions3.new o.reset_defaults o.foo.should == 'FOO' end end describe '#delete' do it "should delete an option" do o = FooOptions.new o.delete(:foo) o.to_hash.should == {} end it "should not error if an option is deleted that does not exist" do o = FooOptions.new o.delete(:foo) o.delete(:foo) o.to_hash.should == {} end end describe '#[]' do it "should handle getting option values using hash syntax" do FooOptions.new[:foo].should == "abc" end end describe '#[]=' do it "should handle setting options using hash syntax" do o = FooOptions.new o[:foo] = "xyz" o[:foo].should == "xyz" end it "should allow setting of unregistered keys" do o = FooOptions.new o[:bar] = "foo" o[:bar].should == "foo" end end describe '#method_missing' do it "should allow setting of unregistered keys" do o = FooOptions.new o.bar = 'foo' o.bar.should == 'foo' end it "should allow getting values of unregistered keys (return nil)" do FooOptions.new.bar.should be_nil end it "should print debugging messages about unregistered keys" do log.should_receive(:debug).with("Attempting to access unregistered key bar on FooOptions") FooOptions.new.bar log.should_receive(:debug).with("Attempting to set unregistered key bar on FooOptions") FooOptions.new.bar = 1 end end describe '#update' do it "should allow updating of options" do FooOptions.new.update(:foo => "xyz").foo.should == "xyz" end it "should not ignore keys with no setter (OpenStruct behaviour)" do o = FooOptions.new o.update(:bar => "xyz") o.to_hash.should == {:foo => "abc", :bar => "xyz"} end end describe '#merge' do it "should update a new object" do o = FooOptions.new o.merge(:foo => "xyz").object_id.should_not == o.object_id o.merge(:foo => "xyz").to_hash.should == {:foo => "xyz"} end it "should add in values from original object" do o = FooOptions.new o.update(:bar => "foo") o.merge(:baz => 1).to_hash.should == {:foo => "abc", :bar => "foo", :baz => 1} end end describe '#to_hash' do it "should convert all instance variables and symbolized keys" do class ToHashOptions1 < YARD::Options attr_accessor :foo, :bar, :baz def initialize; @foo = 1; @bar = 2; @baz = "hello" end end o = ToHashOptions1.new hash = o.to_hash hash.keys.should include(:foo, :bar, :baz) hash[:foo].should == 1 hash[:bar].should == 2 hash[:baz].should == "hello" end it "should use accessor when converting values to hash" do class ToHashOptions2 < YARD::Options def initialize; @foo = 1 end def foo; "HELLO#{@foo}" end end o = ToHashOptions2.new o.to_hash.should == {:foo => "HELLO1"} end it "should ignore ivars with no accessor" do class ToHashOptions3 < YARD::Options attr_accessor :foo def initialize; @foo = 1; @bar = "NOIGNORE" end end o = ToHashOptions3.new o.to_hash.should == {:foo => 1, :bar => "NOIGNORE"} end end describe '#tap' do it "should support #tap(&block) (even in 1.8.6)" do o = FooOptions.new.tap {|o| o.foo = :BAR } o.to_hash.should == {:foo => :BAR} end end end yard-0.8.7.3/spec/server/0000755000004100000410000000000012261240652015116 5ustar www-datawww-datayard-0.8.7.3/spec/server/adapter_spec.rb0000644000004100000410000000213312261240652020074 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::Server::Adapter do after(:all) { Server::Adapter.shutdown } describe '#add_library' do it "should add a library" do lib = LibraryVersion.new('yard') a = Adapter.new({}) a.libraries.should be_empty a.add_library(lib) a.libraries['yard'].should == [lib] end end describe '#start' do it "should not implement #start" do lambda { Adapter.new({}).start }.should raise_error(NotImplementedError) end end describe '.setup' do it 'should add template paths and helpers' do Adapter.setup Templates::Template.extra_includes.should include(DocServerHelper) Templates::Engine.template_paths.should include(YARD::ROOT + '/yard/server/templates') end end describe '.shutdown' do it 'should cleanup template paths and helpers' do Adapter.setup Adapter.shutdown Templates::Template.extra_includes.should_not include(DocServerHelper) Templates::Engine.template_paths.should_not include(YARD::ROOT + '/yard/server/templates') end end endyard-0.8.7.3/spec/server/commands/0000755000004100000410000000000012261240652016717 5ustar www-datawww-datayard-0.8.7.3/spec/server/commands/library_command_spec.rb0000644000004100000410000000177312261240652023430 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' require 'ostruct' describe YARD::Server::Commands::LibraryCommand do before do Templates::Engine.stub!(:render) Templates::Engine.stub!(:generate) YARD.stub!(:parse) Registry.stub!(:load) Registry.stub!(:save) @cmd = LibraryCommand.new(:adapter => mock_adapter) @request = OpenStruct.new(:xhr? => false, :path => "/foo") @library = OpenStruct.new(:source_path => '.') @cmd.library = @library @cmd.stub!(:load_yardoc).and_return(nil) end def call lambda { @cmd.call(@request) }.should raise_error(NotImplementedError) end describe "#call" do it "should raise NotImplementedError" do call end it "should set :rdoc as the default markup in incremental mode" do @cmd.incremental = true call @cmd.options[:markup].should == :rdoc end it "should set :rdoc as the default markup in regular mode" do call @cmd.options[:markup].should == :rdoc end end endyard-0.8.7.3/spec/server/commands/base_spec.rb0000644000004100000410000000515012261240652021171 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' class MyProcCommand < Base def initialize(&block) self.class.send(:define_method, :run, &block) end end class MyCacheCommand < Base def run; cache 'foo' end end describe YARD::Server::Commands::Base do describe '#cache' do before do @command = MyCacheCommand.new(:adapter => mock_adapter, :caching => true) @command.request = OpenStruct.new end it "should not cache if caching == false" do File.should_not_receive(:open) @command.caching = false @command.run end it "should require document root to cache" do File.should_not_receive(:open) @command.adapter.document_root = nil @command.run end it "should cache to path/to/file.html and create directories" do FileUtils.should_receive(:mkdir_p).with('/public/path/to') File.should_receive(:open).with('/public/path/to/file.html', anything) @command.request.path = '/path/to/file.html' @command.run end end describe '#redirect' do it "should return a valid redirection" do cmd = MyProcCommand.new { redirect '/foo' } cmd.call(mock_request('/foo')).should == [302, {"Content-Type" => "text/html", "Location" => "/foo"}, [""]] end end describe '#call' do it "should handle a NotFoundError and use message as body" do cmd = MyProcCommand.new { raise NotFoundError, "hello world" } s, h, b = *cmd.call(mock_request('/foo')) s.should == 404 b.should == ["hello world"] end it "should not use message as body if not provided in NotFoundError" do cmd = MyProcCommand.new { raise NotFoundError } s, h, b = *cmd.call(mock_request('/foo')) s.should == 404 b.should == ["Not found: /foo"] end it "should handle 404 status code from #run" do cmd = MyProcCommand.new { self.status = 404 } s, h, b = *cmd.call(mock_request('/foo')) s.should == 404 b.should == ["Not found: /foo"] end it "should not override body if status is 404 and body is defined" do cmd = MyProcCommand.new { self.body = "foo"; self.status = 404 } s, h, b = *cmd.call(mock_request('/bar')) s.should == 404 b.should == ['foo'] end it "should handle body as Array" do cmd = MyProcCommand.new { self.body = ['a', 'b', 'c'] } s, h, b = *cmd.call(mock_request('/foo')) b.should == %w(a b c) end it "should allow headers to be defined" do cmd = MyProcCommand.new { self.headers['Foo'] = 'BAR' } s, h, b = *cmd.call(mock_request('/foo')) h['Foo'].should == 'BAR' end end endyard-0.8.7.3/spec/server/commands/static_file_command_spec.rb0000644000004100000410000000617312261240652024251 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::Server::Commands::StaticFileCommand do before do adapter = mock_adapter adapter.document_root = '/c' @cmd = StaticFileCommand.new(:adapter => adapter) end describe '#run' do def run(path, status = nil, body = nil) s, h, b = *@cmd.call(mock_request(path)) body.should == b.first if body status.should == s if status [s, h, b] end it "should search through document root before static paths" do File.should_receive(:exist?).with('/c/path/to/file.txt').ordered.and_return(false) StaticFileCommand::STATIC_PATHS.reverse.each do |path| File.should_receive(:exist?).with(File.join(path, 'path/to/file.txt')).ordered.and_return(false) end run '/path/to/file.txt' end it "should return file contents if found" do tpl = Templates::Engine.template(:default, :fulldoc, :html) File.should_receive(:exist?).with('/c/path/to/file.txt').and_return(false) tpl.should_receive(:find_file).with('/path/to/file.txt').and_return('/path/to/foo') File.should_receive(:read).with('/path/to/foo').and_return('FOO') run('/path/to/file.txt', 200, 'FOO') end it "should allow registering of new paths and use those before other static paths" do Server.register_static_path '/foo' path = '/foo/path/to/file.txt' File.should_receive(:exist?).with('/c/path/to/file.txt').and_return(false) File.should_receive(:exist?).with(path).and_return(true) File.should_receive(:read).with(path).and_return('FOO') run('/path/to/file.txt', 200, 'FOO') end it "should not use registered path before docroot" do Server.register_static_path '/foo' path = '/foo/path/to/file.txt' File.should_receive(:exist?).with('/c/path/to/file.txt').and_return(true) File.should_receive(:read).with('/c/path/to/file.txt').and_return('FOO') run('/c/path/to/file.txt', 200, 'FOO') end it "should return 404 if not found" do File.should_receive(:exist?).with('/c/path/to/file.txt').ordered.and_return(false) StaticFileCommand::STATIC_PATHS.reverse.each do |path| File.should_receive(:exist?).with(File.join(path, 'path/to/file.txt')).ordered.and_return(false) end run('/path/to/file.txt', 404) end it "should return text/html for file with no extension" do File.should_receive(:exist?).with('/c/file').and_return(true) File.should_receive(:read).with('/c/file') s, h, b = *run('/file') h['Content-Type'].should == 'text/html' end { "js" => "text/javascript", "css" => "text/css", "png" => "image/png", "gif" => "image/gif", "htm" => "text/html", "html" => "text/html", "txt" => "text/plain", "unknown" => "application/octet-stream" }.each do |ext, mime| it "should serve file.#{ext} as #{mime}" do File.should_receive(:exist?).with('/c/file.' + ext).and_return(true) File.should_receive(:read).with('/c/file.' + ext) s, h, b = *run('/file.' + ext) h['Content-Type'].should == mime end end end endyard-0.8.7.3/spec/server/spec_helper.rb0000644000004100000410000000073612261240652017742 0ustar www-datawww-datarequire File.dirname(__FILE__) + "/../spec_helper" require 'ostruct' include Server include Commands def mock_adapter(opts = {}) opts[:libraries] ||= {'project' => [LibraryVersion.new('project', '1.0.0'), LibraryVersion.new('project', '1.0.1')]} opts[:document_root] ||= '/public' opts[:options] ||= {:single_library => false, :caching => false} opts[:server_options] ||= {} OpenStruct.new(opts) end def mock_request(path = '/') OpenStruct.new(:path => path) end yard-0.8.7.3/spec/server/doc_server_serializer_spec.rb0000644000004100000410000000331612261240652023044 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::Server::DocServerSerializer do describe '#serialized_path' do before do Registry.clear @serializer = Server::DocServerSerializer.new end after(:all) { Server::Adapter.shutdown } it "should return '/PREFIX/library/toplevel' for root" do @serializer.serialized_path(Registry.root).should == "toplevel" end it "should return /PREFIX/library/Object for Object in a library" do @serializer.serialized_path(P('A::B::C')).should == 'A/B/C' end it "should link to instance method as Class:method" do obj = CodeObjects::MethodObject.new(:root, :method) @serializer.serialized_path(obj).should == 'toplevel:method' end it "should link to class method as Class.method" do obj = CodeObjects::MethodObject.new(:root, :method, :class) @serializer.serialized_path(obj).should == 'toplevel.method' end it "should link to anchor for constant" do obj = CodeObjects::ConstantObject.new(:root, :FOO) @serializer.serialized_path(obj).should == 'toplevel#FOO-constant' end it "should link to anchor for class variable" do obj = CodeObjects::ClassVariableObject.new(:root, :@@foo) @serializer.serialized_path(obj).should == 'toplevel#@@foo-classvariable' end it "should link files using file/ prefix" do file = CodeObjects::ExtraFileObject.new('a/b/FooBar.md', '') @serializer.serialized_path(file).should == 'file/FooBar' end it "should handle unicode data" do file = CodeObjects::ExtraFileObject.new("test\u0160", '') @serializer.serialized_path(file).should == 'file/test_C5A0' end if defined?(::Encoding) end endyard-0.8.7.3/spec/server/rack_adapter_spec.rb0000644000004100000410000000130612261240652021075 0ustar www-datawww-datarequire File.dirname(__FILE__) + "/spec_helper" describe "YARD::Server::RackMiddleware" do before do begin; require 'rack'; rescue LoadError; pending "rack required for these tests" end @superapp = mock(:superapp) @app = YARD::Server::RackMiddleware.new(@superapp, :libraries => {'foo' => [LibraryVersion.new('foo', nil)]}) end after(:all) { YARD::Server::Adapter.shutdown } it "should handle requests" do @app.call(Rack::MockRequest.env_for('/'))[0].should == 200 end it "should pass up to the next middleware on 404" do @superapp.should_receive(:call).and_return([200, {}, ['OK']]) @app.call(Rack::MockRequest.env_for('/INVALID')).should == [200, {}, ['OK']] end endyard-0.8.7.3/spec/server/webrick_servlet_spec.rb0000644000004100000410000000117012261240652021646 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::Server::WebrickServlet do describe '#do_GET' do it "should perform a GET" do resp = OpenStruct.new class << resp def []=(name, value) (self.headers ||= {})[name] = value end end server = mock(:server) server.stub!(:[]) adapter = mock_adapter adapter.router = proc { [200, {'Header' => 'foo'}, ['body']]} WebrickServlet.new(server, adapter).do_GET(mock_request('/foo'), resp) resp.status.should == 200 resp.headers.should == {'Header' => 'foo'} resp.body.should == 'body' end end endyard-0.8.7.3/spec/server/doc_server_helper_spec.rb0000644000004100000410000000301112261240652022142 0ustar www-datawww-datarequire File.dirname(__FILE__) + "/spec_helper" class MyDocServerSerializerRouter attr_accessor :request def docs_prefix; 'PREFIX' end def initialize; @request = mock_request end end class MockDocServerHelper include YARD::Templates::Helpers::BaseHelper include YARD::Templates::Helpers::HtmlHelper include YARD::Server::DocServerHelper attr_accessor :adapter attr_accessor :single_library attr_accessor :library def initialize @single_library = false @library = LibraryVersion.new('foo') @adapter = mock_adapter(:router => MyDocServerSerializerRouter.new) @serializer = YARD::Server::DocServerSerializer.new @object = YARD::Registry.root end def options; OpenStruct.new end end describe YARD::Server::DocServerHelper do before do @helper = MockDocServerHelper.new end describe '#url_for' do it "should not link to /library/ if single_library = true" do @helper.single_library = true @helper.url_for(Registry.root).should == "/PREFIX/toplevel" end it "should return /PREFIX/foo/version if foo has a version" do @helper.library = LibraryVersion.new('foo', 'bar') @helper.adapter.router.request.version_supplied = true @helper.url_for(P('A')).should == '/PREFIX/foo/bar/A' end end describe '#url_for_file' do it "should properly link file objects using file/ prefix" do file = CodeObjects::ExtraFileObject.new('a/b/FooBar.md', '') @helper.url_for_file(file).should == '/PREFIX/foo/file/a/b/FooBar.md' end end endyard-0.8.7.3/spec/server/static_caching_spec.rb0000644000004100000410000000256112261240652021424 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::Server::StaticCaching do include StaticCaching describe '#check_static_cache' do def adapter; @adapter ||= mock_adapter end def request; @request ||= OpenStruct.new end it "should return nil if document root is not set" do adapter.document_root = nil check_static_cache.should be_nil end it "should read a file from document root if path matches file on system" do request.path = '/hello/world.html' File.should_receive(:file?).with('/public/hello/world.html').and_return(true) File.should_receive(:open).with('/public/hello/world.html', anything).and_return('body') s, h, b = *check_static_cache s.should == 200 b.should == ["body"] end it "should read a file if path matches file on system + .html" do request.path = '/hello/world' File.should_receive(:file?).with('/public/hello/world.html').and_return(true) File.should_receive(:open).with('/public/hello/world.html', anything).and_return('body') s, h, b = *check_static_cache s.should == 200 b.should == ["body"] end it "should return nil if no matching file is found" do request.path = '/hello/foo' File.should_receive(:file?).with('/public/hello/foo.html').and_return(false) check_static_cache.should == nil end end endyard-0.8.7.3/spec/server/router_spec.rb0000644000004100000410000000763112261240652020004 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' class MyRouterSpecRouter < Router def docs_prefix; 'mydocs/foo' end def list_prefix; 'mylist/foo' end def search_prefix; 'mysearch/foo' end def check_static_cache; nil end end describe YARD::Server::Router do before do @adapter = mock_adapter @projects = @adapter.libraries['project'] @request = mock_request end describe '#parse_library_from_path' do def parse(*args) @request.path = '/' + args.join('/') @router = MyRouterSpecRouter.new(@adapter) @router.request = @request @router.parse_library_from_path(args.flatten) end it "should parse library and version name out of path" do parse('project', '1.0.0').should == [@projects[0], []] @request.version_supplied.should be_true end it "should parse library and use latest version if version is not supplied" do parse('project').should == [@projects[1], []] @request.version_supplied.should be_false end it "should parse library and use latest version if next component is not a version" do parse('project', 'notaversion').should == [@projects[1], ['notaversion']] @request.version_supplied.should be_false end it "should return nil library if no library is found" do parse('notproject').should == [nil, ['notproject']] end it "should not parse library or version if single_library == true" do @adapter.stub!(:options).and_return(:single_library => true) parse('notproject').should == [@projects[0], ['notproject']] end end describe '#route' do def route_to(route, command, *args) req = mock_request(route) router = MyRouterSpecRouter.new(@adapter) command.should_receive(:new).and_return do |*args| @command = command.allocate @command.send(:initialize, *args) class << @command; def call(req); self end end @command end router.call(req) end it "should route /docs/OBJECT to object if single_library = true" do @adapter.stub!(:options).and_return(:single_library => true) route_to('/mydocs/foo/FOO', DisplayObjectCommand) end it "should route /docs" do route_to('/mydocs/foo', LibraryIndexCommand) end it "should route /docs as index for library if single_library == true" do @adapter.stub!(:options).and_return(:single_library => true) route_to('/mydocs/foo/', DisplayObjectCommand) end it "should route /docs/name/version" do route_to('/mydocs/foo/project/1.0.0', DisplayObjectCommand) @command.library.should == @projects[0] end it "should route /docs/name/ to latest version of library" do route_to('/mydocs/foo/project', DisplayObjectCommand) @command.library.should == @projects[1] end it "should route /list/name/version/class" do route_to('/mylist/foo/project/1.0.0/class', ListCommand) @command.library.should == @projects[0] end it "should route /list/name/version/methods" do route_to('/mylist/foo/project/1.0.0/methods', ListCommand) @command.library.should == @projects[0] end it "should route /list/name/version/files" do route_to('/mylist/foo/project/1.0.0/files', ListCommand) @command.library.should == @projects[0] end it "should route /list/name to latest version of library" do route_to('/mylist/foo/project/class', ListCommand) @command.library.should == @projects[1] end it "should route /search/name/version" do route_to('/mysearch/foo/project/1.0.0', SearchCommand) @command.library.should == @projects[0] end it "should route /search/name to latest version of library" do route_to('/mysearch/foo/project', SearchCommand) @command.library.should == @projects[1] end it "should search static files for non-existent library" do route_to('/mydocs/foo/notproject', StaticFileCommand) end end endyard-0.8.7.3/spec/spec_helper.rb0000644000004100000410000000705112261240652016431 0ustar www-datawww-datarequire "rubygems" begin require "rspec" rescue LoadError require "spec" end begin require 'bundler' Bundler.setup rescue LoadError end begin require 'simplecov' SimpleCov.start # TODO: hide some rb files from cov report # hide = '_spec\.rb$,spec_helper\.rb$,ruby_lex\.rb$,autoload\.rb$' # if YARD::Parser::SourceParser.parser_type == :ruby # hide += ',legacy\/.+_handler' # else # hide += ',ruby_parser\.rb$,ast_node\.rb$,handlers\/ruby\/[^\/]+\.rb$' # end rescue LoadError end if ENV['COVERAGE'] require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'yard')) unless defined?(HAVE_RIPPER) begin require 'ripper'; rescue LoadError; end HAVE_RIPPER = defined?(::Ripper) && !ENV['LEGACY'] ? true : false LEGACY_PARSER = !HAVE_RIPPER class YARD::Parser::SourceParser def self.parser_type; :ruby18 end end if ENV['LEGACY'] end def parse_file(file, thisfile = __FILE__, log_level = log.level, ext = '.rb.txt') Registry.clear path = File.join(File.dirname(thisfile), 'examples', file.to_s + ext) YARD::Parser::SourceParser.parse(path, [], log_level) end def described_in_docs(klass, meth, file = nil) YARD::Tags::Library.define_tag "RSpec Specification", :it, :with_raw_title_and_text # Parse the file (could be multiple files) if file filename = File.join(YARD::ROOT, file) YARD::Parser::SourceParser.new.parse(filename) else underscore = klass.class_name.gsub(/([a-z])([A-Z])/, '\1_\2').downcase.gsub('::', '/') $".find_all {|p| p.include? underscore }.each do |filename| next unless File.exist? filename YARD::Parser::SourceParser.new.parse(filename) end end # Get the object objname = klass.name + (meth[0,1] == '#' ? meth : '::' + meth) obj = Registry.at(objname) raise "Cannot find object #{objname} described by spec." unless obj raise "#{obj.path} has no @it tags to spec." unless obj.has_tag? :it # Run examples describe(klass, meth) do obj.tags(:it).each do |it| path = File.relative_path(YARD::ROOT, obj.file) it(it.name + " (from #{path}:#{obj.line})") do begin eval(it.text) rescue => e e.set_backtrace(["#{path}:#{obj.line}:in @it tag specification"]) raise e end end end end end def docspec(objname = self.class.description, klass = self.class.described_type) # Parse the file (could be multiple files) underscore = klass.class_name.gsub(/([a-z])([A-Z])/, '\1_\2').downcase.gsub('::', '/') $".find_all {|p| p.include? underscore }.each do |filename| filename = File.join(YARD::ROOT, filename) next unless File.exist? filename YARD::Parser::SourceParser.new.parse(filename) end # Get the object objname = klass.name + objname if objname =~ /^[^A-Z]/ obj = Registry.at(objname) raise "Cannot find object #{objname} described by spec." unless obj raise "#{obj.path} has no @example tags to spec." unless obj.has_tag? :example # Run examples obj.tags(:example).each do |exs| exs.text.split(/\n/).each do |ex| begin hash = eval("{ #{ex} }") hash.keys.first.should == hash.values.first rescue => e raise e, "#{e.message}\nInvalid spec example in #{objname}:\n\n\t#{ex}\n" end end end end module Kernel require 'cgi' def p(*args) puts args.map {|arg| CGI.escapeHTML(arg.inspect) }.join("
            \n") args.first end def puts(str = '') STDOUT.puts str + "
            \n" str end end if ENV['TM_APP_PATH'] RSpec.configure do |config| config.before(:each) { log.io = StringIO.new } end include YARD yard-0.8.7.3/spec/parser/0000755000004100000410000000000012261240652015104 5ustar www-datawww-datayard-0.8.7.3/spec/parser/examples/0000755000004100000410000000000012261240652016722 5ustar www-datawww-datayard-0.8.7.3/spec/parser/examples/multifile.c.txt0000644000004100000410000000057012261240652021700 0ustar www-datawww-datastruct hoge * rb_fuga(VALUE obj) { return Qtrue; } /* * Hello Mars */ VALUE rb_hello_mars(VALUE obj, VALUE n) { return Qtrue; } void Init_Multifile(void) { rb_cMultifile = rb_define_class("Multifile", rb_cObject); rb_define_method(rb_cMultifile, "extra", rb_extra, 1); /* in extra.c */ rb_define_method(rb_cMultifile, "hello_mars", rb_hello_mars, 1); } yard-0.8.7.3/spec/parser/examples/extrafile.c.txt0000644000004100000410000000010512261240652021663 0ustar www-datawww-data/* * foo */ VALUE rb_extra(VALUE obj, VALUE n) { return Qtrue; } yard-0.8.7.3/spec/parser/examples/example1.rb.txt0000644000004100000410000000011712261240652021600 0ustar www-datawww-datamodule Hello class Hi # Docstring def me "Value" end end endyard-0.8.7.3/spec/parser/examples/parse_in_order_001.rb.txt0000644000004100000410000000003412261240652023435 0ustar www-datawww-dataclass MyModule::MyClass end yard-0.8.7.3/spec/parser/examples/tag_handler_001.rb.txt0000644000004100000410000000007712261240652022721 0ustar www-datawww-dataclass Foo # @api public # @return nil def foo end endyard-0.8.7.3/spec/parser/examples/array.c.txt0000644000004100000410000027421712261240652021037 0ustar www-datawww-data/********************************************************************** array.c - $Author: yugui $ created at: Fri Aug 6 09:46:12 JST 1993 Copyright (C) 1993-2007 Yukihiro Matsumoto Copyright (C) 2000 Network Applied Communication Laboratory, Inc. Copyright (C) 2000 Information-technology Promotion Agency, Japan **********************************************************************/ #include "ruby/ruby.h" #include "ruby/util.h" #include "ruby/st.h" #ifndef ARRAY_DEBUG # define NDEBUG #endif #include VALUE rb_cArray; static ID id_cmp; #define ARY_DEFAULT_SIZE 16 #define ARY_MAX_SIZE (LONG_MAX / sizeof(VALUE)) void rb_mem_clear(register VALUE *mem, register long size) { while (size--) { *mem++ = Qnil; } } static inline void memfill(register VALUE *mem, register long size, register VALUE val) { while (size--) { *mem++ = val; } } # define ARY_SHARED_P(ary) \ (assert(!FL_TEST(ary, ELTS_SHARED) || !FL_TEST(ary, RARRAY_EMBED_FLAG)), \ FL_TEST(ary,ELTS_SHARED)) # define ARY_EMBED_P(ary) \ (assert(!FL_TEST(ary, ELTS_SHARED) || !FL_TEST(ary, RARRAY_EMBED_FLAG)), \ FL_TEST(ary, RARRAY_EMBED_FLAG)) #define ARY_HEAP_PTR(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.ptr) #define ARY_HEAP_LEN(a) (assert(!ARY_EMBED_P(a)), RARRAY(a)->as.heap.len) #define ARY_EMBED_PTR(a) (assert(ARY_EMBED_P(a)), RARRAY(a)->as.ary) #define ARY_EMBED_LEN(a) \ (assert(ARY_EMBED_P(a)), \ (long)((RBASIC(a)->flags >> RARRAY_EMBED_LEN_SHIFT) & \ (RARRAY_EMBED_LEN_MASK >> RARRAY_EMBED_LEN_SHIFT))) #define ARY_OWNS_HEAP_P(a) (!FL_TEST(a, ELTS_SHARED|RARRAY_EMBED_FLAG)) #define FL_SET_EMBED(a) do { \ assert(!ARY_SHARED_P(a)); \ assert(!OBJ_FROZEN(a)); \ FL_SET(a, RARRAY_EMBED_FLAG); \ } while (0) #define FL_UNSET_EMBED(ary) FL_UNSET(ary, RARRAY_EMBED_FLAG|RARRAY_EMBED_LEN_MASK) #define FL_SET_SHARED(ary) do { \ assert(!ARY_EMBED_P(ary)); \ FL_SET(ary, ELTS_SHARED); \ } while (0) #define FL_UNSET_SHARED(ary) FL_UNSET(ary, ELTS_SHARED) #define ARY_SET_PTR(ary, p) do { \ assert(!ARY_EMBED_P(ary)); \ assert(!OBJ_FROZEN(ary)); \ RARRAY(ary)->as.heap.ptr = (p); \ } while (0) #define ARY_SET_EMBED_LEN(ary, n) do { \ long tmp_n = n; \ assert(ARY_EMBED_P(ary)); \ assert(!OBJ_FROZEN(ary)); \ RBASIC(ary)->flags &= ~RARRAY_EMBED_LEN_MASK; \ RBASIC(ary)->flags |= (tmp_n) << RARRAY_EMBED_LEN_SHIFT; \ } while (0) #define ARY_SET_HEAP_LEN(ary, n) do { \ assert(!ARY_EMBED_P(ary)); \ RARRAY(ary)->as.heap.len = n; \ } while (0) #define ARY_SET_LEN(ary, n) do { \ if (ARY_EMBED_P(ary)) { \ ARY_SET_EMBED_LEN(ary, n); \ } \ else { \ ARY_SET_HEAP_LEN(ary, n); \ } \ assert(RARRAY_LEN(ary) == n); \ } while (0) #define ARY_INCREASE_PTR(ary, n) do { \ assert(!ARY_EMBED_P(ary)); \ assert(!OBJ_FROZEN(ary)); \ RARRAY(ary)->as.heap.ptr += n; \ } while (0) #define ARY_INCREASE_LEN(ary, n) do { \ assert(!OBJ_FROZEN(ary)); \ if (ARY_EMBED_P(ary)) { \ ARY_SET_EMBED_LEN(ary, RARRAY_LEN(ary)+n); \ } \ else { \ RARRAY(ary)->as.heap.len += n; \ } \ } while (0) #define ARY_CAPA(ary) (ARY_EMBED_P(ary) ? RARRAY_EMBED_LEN_MAX : \ ARY_SHARED_ROOT_P(ary) ? RARRAY_LEN(ary) : RARRAY(ary)->as.heap.aux.capa) #define ARY_SET_CAPA(ary, n) do { \ assert(!ARY_EMBED_P(ary)); \ assert(!ARY_SHARED_P(ary)); \ assert(!OBJ_FROZEN(ary)); \ RARRAY(ary)->as.heap.aux.capa = (n); \ } while (0) #define ARY_SHARED(ary) (assert(ARY_SHARED_P(ary)), RARRAY(ary)->as.heap.aux.shared) #define ARY_SET_SHARED(ary, value) do { \ assert(!ARY_EMBED_P(ary)); \ assert(ARY_SHARED_P(ary)); \ assert(ARY_SHARED_ROOT_P(value)); \ RARRAY(ary)->as.heap.aux.shared = (value); \ } while (0) #define RARRAY_SHARED_ROOT_FLAG FL_USER5 #define ARY_SHARED_ROOT_P(ary) (FL_TEST(ary, RARRAY_SHARED_ROOT_FLAG)) #define ARY_SHARED_NUM(ary) \ (assert(ARY_SHARED_ROOT_P(ary)), RARRAY(ary)->as.heap.aux.capa) #define ARY_SET_SHARED_NUM(ary, value) do { \ assert(ARY_SHARED_ROOT_P(ary)); \ RARRAY(ary)->as.heap.aux.capa = (value); \ } while (0) #define FL_SET_SHARED_ROOT(ary) do { \ assert(!ARY_EMBED_P(ary)); \ FL_SET(ary, RARRAY_SHARED_ROOT_FLAG); \ } while (0) static void ary_resize_capa(VALUE ary, long capacity) { assert(RARRAY_LEN(ary) <= capacity); assert(!OBJ_FROZEN(ary)); assert(!ARY_SHARED_P(ary)); if (capacity > RARRAY_EMBED_LEN_MAX) { if (ARY_EMBED_P(ary)) { long len = ARY_EMBED_LEN(ary); VALUE *ptr = ALLOC_N(VALUE, (capacity)); MEMCPY(ptr, ARY_EMBED_PTR(ary), VALUE, len); FL_UNSET_EMBED(ary); ARY_SET_PTR(ary, ptr); ARY_SET_HEAP_LEN(ary, len); } else { REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, (capacity)); } ARY_SET_CAPA(ary, (capacity)); } else { if (!ARY_EMBED_P(ary)) { long len = RARRAY_LEN(ary); VALUE *ptr = RARRAY_PTR(ary); MEMCPY(RARRAY(ary)->as.ary, ptr, VALUE, len); FL_SET_EMBED(ary); ARY_SET_LEN(ary, len); xfree(ptr); } } } static void rb_ary_decrement_share(VALUE shared) { if (shared) { int num = ARY_SHARED_NUM(shared) - 1; if (num == 0) { rb_ary_free(shared); rb_gc_force_recycle(shared); } else if (num > 0) { ARY_SET_SHARED_NUM(shared, num); } } } static void rb_ary_unshare(VALUE ary) { VALUE shared = RARRAY(ary)->as.heap.aux.shared; rb_ary_decrement_share(shared); FL_UNSET_SHARED(ary); } static inline void rb_ary_unshare_safe(VALUE ary) { if (ARY_SHARED_P(ary) && !ARY_EMBED_P(ary)) { rb_ary_unshare(ary); } } static VALUE rb_ary_increment_share(VALUE shared) { int num = ARY_SHARED_NUM(shared); if (num >= 0) { ARY_SET_SHARED_NUM(shared, num + 1); } return shared; } static void rb_ary_set_shared(VALUE ary, VALUE shared) { rb_ary_increment_share(shared); FL_SET_SHARED(ary); ARY_SET_SHARED(ary, shared); } static inline void rb_ary_modify_check(VALUE ary) { if (OBJ_FROZEN(ary)) rb_error_frozen("array"); if (!OBJ_UNTRUSTED(ary) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify array"); } static void rb_ary_modify(VALUE ary) { rb_ary_modify_check(ary); if (ARY_SHARED_P(ary)) { long len = RARRAY_LEN(ary); if (len <= RARRAY_EMBED_LEN_MAX) { VALUE *ptr = ARY_HEAP_PTR(ary); VALUE shared = ARY_SHARED(ary); FL_UNSET_SHARED(ary); FL_SET_EMBED(ary); MEMCPY(ARY_EMBED_PTR(ary), ptr, VALUE, len); rb_ary_decrement_share(shared); ARY_SET_EMBED_LEN(ary, len); } else { VALUE *ptr = ALLOC_N(VALUE, len); MEMCPY(ptr, RARRAY_PTR(ary), VALUE, len); rb_ary_unshare(ary); ARY_SET_CAPA(ary, len); ARY_SET_PTR(ary, ptr); } } } VALUE rb_ary_freeze(VALUE ary) { return rb_obj_freeze(ary); } /* * call-seq: * array.frozen? -> true or false * * Return true if this array is frozen (or temporarily frozen * while being sorted). */ static VALUE rb_ary_frozen_p(VALUE ary) { if (OBJ_FROZEN(ary)) return Qtrue; return Qfalse; } static VALUE ary_alloc(VALUE klass) { NEWOBJ(ary, struct RArray); OBJSETUP(ary, klass, T_ARRAY); FL_SET_EMBED((VALUE)ary); ARY_SET_EMBED_LEN((VALUE)ary, 0); return (VALUE)ary; } static VALUE ary_new(VALUE klass, long len) { VALUE ary; if (len < 0) { rb_raise(rb_eArgError, "negative array size (or size too big)"); } if (len > ARY_MAX_SIZE) { rb_raise(rb_eArgError, "array size too big"); } ary = ary_alloc(klass); if (len > RARRAY_EMBED_LEN_MAX) { FL_UNSET_EMBED(ary); ARY_SET_PTR(ary, ALLOC_N(VALUE, len)); ARY_SET_CAPA(ary, len); ARY_SET_HEAP_LEN(ary, 0); } return ary; } VALUE rb_ary_new2(long len) { return ary_new(rb_cArray, len); } VALUE rb_ary_new(void) { return rb_ary_new2(RARRAY_EMBED_LEN_MAX); } #include VALUE rb_ary_new3(long n, ...) { va_list ar; VALUE ary; long i; ary = rb_ary_new2(n); va_start(ar, n); for (i=0; i 0 && elts) { MEMCPY(RARRAY_PTR(ary), elts, VALUE, n); ARY_SET_LEN(ary, n); } return ary; } VALUE rb_ary_tmp_new(long len) { return ary_new(0, len); } void rb_ary_free(VALUE ary) { if (ARY_OWNS_HEAP_P(ary)) { xfree(RARRAY_PTR(ary)); } } static VALUE ary_make_shared(VALUE ary) { assert(!ARY_EMBED_P(ary)); if (ARY_SHARED_P(ary)) { return ARY_SHARED(ary); } else { NEWOBJ(shared, struct RArray); OBJSETUP(shared, 0, T_ARRAY); FL_UNSET_EMBED(shared); ARY_SET_LEN((VALUE)shared, RARRAY_LEN(ary)); ARY_SET_PTR((VALUE)shared, RARRAY_PTR(ary)); FL_SET_SHARED_ROOT(shared); ARY_SET_SHARED_NUM((VALUE)shared, 1); FL_SET_SHARED(ary); ARY_SET_SHARED(ary, (VALUE)shared); OBJ_FREEZE(shared); return (VALUE)shared; } } static VALUE ary_make_substitution(VALUE ary) { if (RARRAY_LEN(ary) <= RARRAY_EMBED_LEN_MAX) { VALUE subst = rb_ary_new2(RARRAY_LEN(ary)); MEMCPY(ARY_EMBED_PTR(subst), RARRAY_PTR(ary), VALUE, RARRAY_LEN(ary)); ARY_SET_EMBED_LEN(subst, RARRAY_LEN(ary)); return subst; } else { return rb_ary_increment_share(ary_make_shared(ary)); } } VALUE rb_assoc_new(VALUE car, VALUE cdr) { return rb_ary_new3(2, car, cdr); } static VALUE to_ary(VALUE ary) { return rb_convert_type(ary, T_ARRAY, "Array", "to_ary"); } VALUE rb_check_array_type(VALUE ary) { return rb_check_convert_type(ary, T_ARRAY, "Array", "to_ary"); } /* * call-seq: * Array.try_convert(obj) -> array or nil * * Try to convert obj into an array, using to_ary method. * Returns converted array or nil if obj cannot be converted * for any reason. This method is to check if an argument is an * array. * * Array.try_convert([1]) # => [1] * Array.try_convert("1") # => nil * * if tmp = Array.try_convert(arg) * # the argument is an array * elsif tmp = String.try_convert(arg) * # the argument is a string * end * */ static VALUE rb_ary_s_try_convert(VALUE dummy, VALUE ary) { return rb_check_array_type(ary); } /* * call-seq: * Array.new(size=0, obj=nil) * Array.new(array) * Array.new(size) {|index| block } * * Returns a new array. In the first form, the new array is * empty. In the second it is created with _size_ copies of _obj_ * (that is, _size_ references to the same * _obj_). The third form creates a copy of the array * passed as a parameter (the array is generated by calling * to_ary on the parameter). In the last form, an array * of the given size is created. Each element in this array is * calculated by passing the element's index to the given block and * storing the return value. * * Array.new * Array.new(2) * Array.new(5, "A") * * # only one copy of the object is created * a = Array.new(2, Hash.new) * a[0]['cat'] = 'feline' * a * a[1]['cat'] = 'Felix' * a * * # here multiple copies are created * a = Array.new(2) { Hash.new } * a[0]['cat'] = 'feline' * a * * squares = Array.new(5) {|i| i*i} * squares * * copy = Array.new(squares) */ static VALUE rb_ary_initialize(int argc, VALUE *argv, VALUE ary) { long len; VALUE size, val; rb_ary_modify(ary); if (argc == 0) { if (ARY_OWNS_HEAP_P(ary) && RARRAY_PTR(ary)) { xfree(RARRAY_PTR(ary)); } rb_ary_unshare_safe(ary); FL_SET_EMBED(ary); ARY_SET_EMBED_LEN(ary, 0); if (rb_block_given_p()) { rb_warning("given block not used"); } return ary; } rb_scan_args(argc, argv, "02", &size, &val); if (argc == 1 && !FIXNUM_P(size)) { val = rb_check_array_type(size); if (!NIL_P(val)) { rb_ary_replace(ary, val); return ary; } } len = NUM2LONG(size); if (len < 0) { rb_raise(rb_eArgError, "negative array size"); } if (len > ARY_MAX_SIZE) { rb_raise(rb_eArgError, "array size too big"); } rb_ary_modify(ary); ary_resize_capa(ary, len); if (rb_block_given_p()) { long i; if (argc == 2) { rb_warn("block supersedes default value argument"); } for (i=0; i 0 && argv) { MEMCPY(RARRAY_PTR(ary), argv, VALUE, argc); ARY_SET_LEN(ary, argc); } return ary; } void rb_ary_store(VALUE ary, long idx, VALUE val) { if (idx < 0) { idx += RARRAY_LEN(ary); if (idx < 0) { rb_raise(rb_eIndexError, "index %ld out of array", idx - RARRAY_LEN(ary)); } } else if (idx >= ARY_MAX_SIZE) { rb_raise(rb_eIndexError, "index %ld too big", idx); } rb_ary_modify(ary); if (idx >= ARY_CAPA(ary)) { long new_capa = ARY_CAPA(ary) / 2; if (new_capa < ARY_DEFAULT_SIZE) { new_capa = ARY_DEFAULT_SIZE; } if (new_capa >= ARY_MAX_SIZE - idx) { new_capa = (ARY_MAX_SIZE - idx) / 2; } new_capa += idx; ary_resize_capa(ary, new_capa); } if (idx > RARRAY_LEN(ary)) { rb_mem_clear(RARRAY_PTR(ary) + RARRAY_LEN(ary), idx-RARRAY_LEN(ary) + 1); } if (idx >= RARRAY_LEN(ary)) { ARY_SET_LEN(ary, idx + 1); } RARRAY_PTR(ary)[idx] = val; } static VALUE ary_make_partial(VALUE ary, VALUE klass, long offset, long len) { assert(offset >= 0); assert(len >= 0); assert(offset+len <= RARRAY_LEN(ary)); if (len <= RARRAY_EMBED_LEN_MAX) { VALUE result = ary_alloc(klass); MEMCPY(ARY_EMBED_PTR(result), RARRAY_PTR(ary) + offset, VALUE, len); ARY_SET_EMBED_LEN(result, len); return result; } else { VALUE shared, result = ary_alloc(klass); FL_UNSET_EMBED(result); shared = ary_make_shared(ary); ARY_SET_PTR(result, RARRAY_PTR(ary)); ARY_SET_LEN(result, RARRAY_LEN(ary)); rb_ary_set_shared(result, shared); ARY_INCREASE_PTR(result, offset); ARY_SET_LEN(result, len); return result; } } static VALUE ary_make_shared_copy(VALUE ary) { return ary_make_partial(ary, rb_obj_class(ary), 0, RARRAY_LEN(ary)); } enum ary_take_pos_flags { ARY_TAKE_FIRST = 0, ARY_TAKE_LAST = 1 }; static VALUE ary_take_first_or_last(int argc, VALUE *argv, VALUE ary, enum ary_take_pos_flags last) { VALUE nv; long n; long offset = 0; rb_scan_args(argc, argv, "1", &nv); n = NUM2LONG(nv); if (n > RARRAY_LEN(ary)) { n = RARRAY_LEN(ary); } else if (n < 0) { rb_raise(rb_eArgError, "negative array size"); } if (last) { offset = RARRAY_LEN(ary) - n; } return ary_make_partial(ary, rb_cArray, offset, n); } /* * call-seq: * array << obj -> array * * Append---Pushes the given object on to the end of this array. This * expression returns the array itself, so several appends * may be chained together. * * [ 1, 2 ] << "c" << "d" << [ 3, 4 ] * #=> [ 1, 2, "c", "d", [ 3, 4 ] ] * */ VALUE rb_ary_push(VALUE ary, VALUE item) { rb_ary_store(ary, RARRAY_LEN(ary), item); return ary; } /* * call-seq: * array.push(obj, ... ) -> array * * Append---Pushes the given object(s) on to the end of this array. This * expression returns the array itself, so several appends * may be chained together. * * a = [ "a", "b", "c" ] * a.push("d", "e", "f") * #=> ["a", "b", "c", "d", "e", "f"] */ static VALUE rb_ary_push_m(int argc, VALUE *argv, VALUE ary) { rb_ary_modify_check(ary); while (argc--) { rb_ary_push(ary, *argv++); } return ary; } VALUE rb_ary_pop(VALUE ary) { long n; rb_ary_modify_check(ary); if (RARRAY_LEN(ary) == 0) return Qnil; if (ARY_OWNS_HEAP_P(ary) && RARRAY_LEN(ary) * 3 < ARY_CAPA(ary) && ARY_CAPA(ary) > ARY_DEFAULT_SIZE) { ary_resize_capa(ary, RARRAY_LEN(ary) * 2); } n = RARRAY_LEN(ary)-1; ARY_SET_LEN(ary, n); return RARRAY_PTR(ary)[n]; } /* * call-seq: * array.pop -> obj or nil * array.pop(n) -> array * * Removes the last element from self and returns it, or * nil if the array is empty. * * If a number _n_ is given, returns an array of the last n elements * (or less) just like array.slice!(-n, n) does. * * a = [ "a", "b", "c", "d" ] * a.pop #=> "d" * a.pop(2) #=> ["b", "c"] * a #=> ["a"] */ static VALUE rb_ary_pop_m(int argc, VALUE *argv, VALUE ary) { VALUE result; if (argc == 0) { return rb_ary_pop(ary); } rb_ary_modify_check(ary); result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST); ARY_INCREASE_LEN(ary, -RARRAY_LEN(result)); return result; } VALUE rb_ary_shift(VALUE ary) { VALUE top; rb_ary_modify_check(ary); if (RARRAY_LEN(ary) == 0) return Qnil; top = RARRAY_PTR(ary)[0]; if (!ARY_SHARED_P(ary)) { if (RARRAY_LEN(ary) < ARY_DEFAULT_SIZE) { MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+1, VALUE, RARRAY_LEN(ary)-1); ARY_INCREASE_LEN(ary, -1); return top; } assert(!ARY_EMBED_P(ary)); /* ARY_EMBED_LEN_MAX < ARY_DEFAULT_SIZE */ RARRAY_PTR(ary)[0] = Qnil; ary_make_shared(ary); } ARY_INCREASE_PTR(ary, 1); /* shift ptr */ ARY_INCREASE_LEN(ary, -1); return top; } /* * call-seq: * array.shift -> obj or nil * array.shift(n) -> array * * Returns the first element of self and removes it (shifting all * other elements down by one). Returns nil if the array * is empty. * * If a number _n_ is given, returns an array of the first n elements * (or less) just like array.slice!(0, n) does. * * args = [ "-m", "-q", "filename" ] * args.shift #=> "-m" * args #=> ["-q", "filename"] * * args = [ "-m", "-q", "filename" ] * args.shift(2) #=> ["-m", "-q"] * args #=> ["filename"] */ static VALUE rb_ary_shift_m(int argc, VALUE *argv, VALUE ary) { VALUE result; long n; if (argc == 0) { return rb_ary_shift(ary); } rb_ary_modify_check(ary); result = ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST); n = RARRAY_LEN(result); if (ARY_SHARED_P(ary)) { ARY_INCREASE_PTR(ary, n); } else { MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+n, VALUE, RARRAY_LEN(ary)-n); } ARY_INCREASE_LEN(ary, -n); return result; } /* * call-seq: * array.unshift(obj, ...) -> array * * Prepends objects to the front of array. * other elements up one. * * a = [ "b", "c", "d" ] * a.unshift("a") #=> ["a", "b", "c", "d"] * a.unshift(1, 2) #=> [ 1, 2, "a", "b", "c", "d"] */ static VALUE rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary) { long len; if (argc == 0) return ary; rb_ary_modify(ary); if (ARY_CAPA(ary) <= (len = RARRAY_LEN(ary)) + argc) { ary_resize_capa(ary, len + argc + ARY_DEFAULT_SIZE); } /* sliding items */ MEMMOVE(RARRAY_PTR(ary) + argc, RARRAY_PTR(ary), VALUE, len); MEMCPY(RARRAY_PTR(ary), argv, VALUE, argc); ARY_INCREASE_LEN(ary, argc); return ary; } VALUE rb_ary_unshift(VALUE ary, VALUE item) { return rb_ary_unshift_m(1,&item,ary); } /* faster version - use this if you don't need to treat negative offset */ static inline VALUE rb_ary_elt(VALUE ary, long offset) { if (RARRAY_LEN(ary) == 0) return Qnil; if (offset < 0 || RARRAY_LEN(ary) <= offset) { return Qnil; } return RARRAY_PTR(ary)[offset]; } VALUE rb_ary_entry(VALUE ary, long offset) { if (offset < 0) { offset += RARRAY_LEN(ary); } return rb_ary_elt(ary, offset); } VALUE rb_ary_subseq(VALUE ary, long beg, long len) { VALUE klass; if (beg > RARRAY_LEN(ary)) return Qnil; if (beg < 0 || len < 0) return Qnil; if (RARRAY_LEN(ary) < len || RARRAY_LEN(ary) < beg + len) { len = RARRAY_LEN(ary) - beg; } klass = rb_obj_class(ary); if (len == 0) return ary_new(klass, 0); return ary_make_partial(ary, klass, beg, len); } /* * call-seq: * array[index] -> obj or nil * array[start, length] -> an_array or nil * array[range] -> an_array or nil * array.slice(index) -> obj or nil * array.slice(start, length) -> an_array or nil * array.slice(range) -> an_array or nil * * Element Reference---Returns the element at _index_, * or returns a subarray starting at _start_ and * continuing for _length_ elements, or returns a subarray * specified by _range_. * Negative indices count backward from the end of the * array (-1 is the last element). Returns nil if the index * (or starting index) are out of range. * * a = [ "a", "b", "c", "d", "e" ] * a[2] + a[0] + a[1] #=> "cab" * a[6] #=> nil * a[1, 2] #=> [ "b", "c" ] * a[1..3] #=> [ "b", "c", "d" ] * a[4..7] #=> [ "e" ] * a[6..10] #=> nil * a[-3, 3] #=> [ "c", "d", "e" ] * # special cases * a[5] #=> nil * a[5, 1] #=> [] * a[5..10] #=> [] * */ VALUE rb_ary_aref(int argc, VALUE *argv, VALUE ary) { VALUE arg; long beg, len; if (argc == 2) { beg = NUM2LONG(argv[0]); len = NUM2LONG(argv[1]); if (beg < 0) { beg += RARRAY_LEN(ary); } return rb_ary_subseq(ary, beg, len); } if (argc != 1) { rb_scan_args(argc, argv, "11", 0, 0); } arg = argv[0]; /* special case - speeding up */ if (FIXNUM_P(arg)) { return rb_ary_entry(ary, FIX2LONG(arg)); } /* check if idx is Range */ switch (rb_range_beg_len(arg, &beg, &len, RARRAY_LEN(ary), 0)) { case Qfalse: break; case Qnil: return Qnil; default: return rb_ary_subseq(ary, beg, len); } return rb_ary_entry(ary, NUM2LONG(arg)); } /* * call-seq: * array.at(index) -> obj or nil * * Returns the element at _index_. A * negative index counts from the end of _self_. Returns +nil+ * if the index is out of range. See also Array#[]. * * a = [ "a", "b", "c", "d", "e" ] * a.at(0) #=> "a" * a.at(-1) #=> "e" */ static VALUE rb_ary_at(VALUE ary, VALUE pos) { return rb_ary_entry(ary, NUM2LONG(pos)); } /* * call-seq: * array.first -> obj or nil * array.first(n) -> an_array * * Returns the first element, or the first +n+ elements, of the array. * If the array is empty, the first form returns nil, and the * second form returns an empty array. * * a = [ "q", "r", "s", "t" ] * a.first #=> "q" * a.first(2) #=> ["q", "r"] */ static VALUE rb_ary_first(int argc, VALUE *argv, VALUE ary) { if (argc == 0) { if (RARRAY_LEN(ary) == 0) return Qnil; return RARRAY_PTR(ary)[0]; } else { return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST); } } /* * call-seq: * array.last -> obj or nil * array.last(n) -> an_array * * Returns the last element(s) of self. If the array is empty, * the first form returns nil. * * a = [ "w", "x", "y", "z" ] * a.last #=> "z" * a.last(2) #=> ["y", "z"] */ VALUE rb_ary_last(int argc, VALUE *argv, VALUE ary) { if (argc == 0) { if (RARRAY_LEN(ary) == 0) return Qnil; return RARRAY_PTR(ary)[RARRAY_LEN(ary)-1]; } else { return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST); } } /* * call-seq: * array.fetch(index) -> obj * array.fetch(index, default ) -> obj * array.fetch(index) {|index| block } -> obj * * Tries to return the element at position index. If the index * lies outside the array, the first form throws an * IndexError exception, the second form returns * default, and the third form returns the value of invoking * the block, passing in the index. Negative values of index * count from the end of the array. * * a = [ 11, 22, 33, 44 ] * a.fetch(1) #=> 22 * a.fetch(-1) #=> 44 * a.fetch(4, 'cat') #=> "cat" * a.fetch(4) { |i| i*i } #=> 16 */ static VALUE rb_ary_fetch(int argc, VALUE *argv, VALUE ary) { VALUE pos, ifnone; long block_given; long idx; rb_scan_args(argc, argv, "11", &pos, &ifnone); block_given = rb_block_given_p(); if (block_given && argc == 2) { rb_warn("block supersedes default value argument"); } idx = NUM2LONG(pos); if (idx < 0) { idx += RARRAY_LEN(ary); } if (idx < 0 || RARRAY_LEN(ary) <= idx) { if (block_given) return rb_yield(pos); if (argc == 1) { rb_raise(rb_eIndexError, "index %ld out of array", idx); } return ifnone; } return RARRAY_PTR(ary)[idx]; } /* * call-seq: * array.index(obj) -> int or nil * array.index {|item| block} -> int or nil * * Returns the index of the first object in self such that is * == to obj. If a block is given instead of an * argument, returns first object for which block is true. * Returns nil if no match is found. * * a = [ "a", "b", "c" ] * a.index("b") #=> 1 * a.index("z") #=> nil * a.index{|x|x=="b"} #=> 1 * * This is an alias of #find_index. */ static VALUE rb_ary_index(int argc, VALUE *argv, VALUE ary) { VALUE val; long i; if (argc == 0) { RETURN_ENUMERATOR(ary, 0, 0); for (i=0; i int or nil * * Returns the index of the last object in array * == to obj. If a block is given instead of an * argument, returns first object for which block is * true. Returns nil if no match is found. * * a = [ "a", "b", "b", "b", "c" ] * a.rindex("b") #=> 3 * a.rindex("z") #=> nil * a.rindex{|x|x=="b"} #=> 3 */ static VALUE rb_ary_rindex(int argc, VALUE *argv, VALUE ary) { VALUE val; long i = RARRAY_LEN(ary); if (argc == 0) { RETURN_ENUMERATOR(ary, 0, 0); while (i--) { if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) return LONG2NUM(i); if (i > RARRAY_LEN(ary)) { i = RARRAY_LEN(ary); } } return Qnil; } rb_scan_args(argc, argv, "01", &val); while (i--) { if (rb_equal(RARRAY_PTR(ary)[i], val)) return LONG2NUM(i); if (i > RARRAY_LEN(ary)) { i = RARRAY_LEN(ary); } } return Qnil; } VALUE rb_ary_to_ary(VALUE obj) { if (TYPE(obj) == T_ARRAY) { return obj; } if (rb_respond_to(obj, rb_intern("to_ary"))) { return to_ary(obj); } return rb_ary_new3(1, obj); } static void rb_ary_splice(VALUE ary, long beg, long len, VALUE rpl) { long rlen; if (len < 0) rb_raise(rb_eIndexError, "negative length (%ld)", len); if (beg < 0) { beg += RARRAY_LEN(ary); if (beg < 0) { beg -= RARRAY_LEN(ary); rb_raise(rb_eIndexError, "index %ld out of array", beg); } } if (RARRAY_LEN(ary) < len || RARRAY_LEN(ary) < beg + len) { len = RARRAY_LEN(ary) - beg; } if (rpl == Qundef) { rlen = 0; } else { rpl = rb_ary_to_ary(rpl); rlen = RARRAY_LEN(rpl); } rb_ary_modify(ary); if (beg >= RARRAY_LEN(ary)) { if (beg > ARY_MAX_SIZE - rlen) { rb_raise(rb_eIndexError, "index %ld too big", beg); } len = beg + rlen; if (len >= ARY_CAPA(ary)) { ary_resize_capa(ary, len); } rb_mem_clear(RARRAY_PTR(ary) + RARRAY_LEN(ary), beg - RARRAY_LEN(ary)); if (rlen > 0) { MEMCPY(RARRAY_PTR(ary) + beg, RARRAY_PTR(rpl), VALUE, rlen); } ARY_SET_LEN(ary, len); } else { long alen; alen = RARRAY_LEN(ary) + rlen - len; if (alen >= ARY_CAPA(ary)) { ary_resize_capa(ary, alen); } if (len != rlen) { MEMMOVE(RARRAY_PTR(ary) + beg + rlen, RARRAY_PTR(ary) + beg + len, VALUE, RARRAY_LEN(ary) - (beg + len)); ARY_SET_LEN(ary, alen); } if (rlen > 0) { MEMMOVE(RARRAY_PTR(ary) + beg, RARRAY_PTR(rpl), VALUE, rlen); } } } /* * call-seq: * array[index] = obj -> obj * array[start, length] = obj or an_array or nil -> obj or an_array or nil * array[range] = obj or an_array or nil -> obj or an_array or nil * * Element Assignment---Sets the element at _index_, * or replaces a subarray starting at _start_ and * continuing for _length_ elements, or replaces a subarray * specified by _range_. If indices are greater than * the current capacity of the array, the array grows * automatically. A negative indices will count backward * from the end of the array. Inserts elements if _length_ is * zero. An +IndexError+ is raised if a negative index points * past the beginning of the array. See also * Array#push, and Array#unshift. * * a = Array.new * a[4] = "4"; #=> [nil, nil, nil, nil, "4"] * a[0, 3] = [ 'a', 'b', 'c' ] #=> ["a", "b", "c", nil, "4"] * a[1..2] = [ 1, 2 ] #=> ["a", 1, 2, nil, "4"] * a[0, 2] = "?" #=> ["?", 2, nil, "4"] * a[0..2] = "A" #=> ["A", "4"] * a[-1] = "Z" #=> ["A", "Z"] * a[1..-1] = nil #=> ["A", nil] * a[1..-1] = [] #=> ["A"] */ static VALUE rb_ary_aset(int argc, VALUE *argv, VALUE ary) { long offset, beg, len; if (argc == 3) { beg = NUM2LONG(argv[0]); len = NUM2LONG(argv[1]); rb_ary_splice(ary, beg, len, argv[2]); return argv[2]; } if (argc != 2) { rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)", argc); } if (FIXNUM_P(argv[0])) { offset = FIX2LONG(argv[0]); goto fixnum; } if (rb_range_beg_len(argv[0], &beg, &len, RARRAY_LEN(ary), 1)) { /* check if idx is Range */ rb_ary_splice(ary, beg, len, argv[1]); return argv[1]; } offset = NUM2LONG(argv[0]); fixnum: rb_ary_store(ary, offset, argv[1]); return argv[1]; } /* * call-seq: * array.insert(index, obj...) -> array * * Inserts the given values before the element with the given index * (which may be negative). * * a = %w{ a b c d } * a.insert(2, 99) #=> ["a", "b", 99, "c", "d"] * a.insert(-2, 1, 2, 3) #=> ["a", "b", 99, "c", 1, 2, 3, "d"] */ static VALUE rb_ary_insert(int argc, VALUE *argv, VALUE ary) { long pos; if (argc == 1) return ary; if (argc < 1) { rb_raise(rb_eArgError, "wrong number of arguments (at least 1)"); } pos = NUM2LONG(argv[0]); if (pos == -1) { pos = RARRAY_LEN(ary); } if (pos < 0) { pos++; } rb_ary_splice(ary, pos, 0, rb_ary_new4(argc - 1, argv + 1)); return ary; } /* * call-seq: * array.each {|item| block } -> array * * Calls block once for each element in self, passing that * element as a parameter. * * a = [ "a", "b", "c" ] * a.each {|x| print x, " -- " } * * produces: * * a -- b -- c -- */ VALUE rb_ary_each(VALUE ary) { long i; RETURN_ENUMERATOR(ary, 0, 0); for (i=0; i array * * Same as Array#each, but passes the index of the element * instead of the element itself. * * a = [ "a", "b", "c" ] * a.each_index {|x| print x, " -- " } * * produces: * * 0 -- 1 -- 2 -- */ static VALUE rb_ary_each_index(VALUE ary) { long i; RETURN_ENUMERATOR(ary, 0, 0); for (i=0; iArray#each
            , but traverses self in reverse * order. * * a = [ "a", "b", "c" ] * a.reverse_each {|x| print x, " " } * * produces: * * c b a */ static VALUE rb_ary_reverse_each(VALUE ary) { long len; RETURN_ENUMERATOR(ary, 0, 0); len = RARRAY_LEN(ary); while (len--) { rb_yield(RARRAY_PTR(ary)[len]); if (RARRAY_LEN(ary) < len) { len = RARRAY_LEN(ary); } } return ary; } /* * call-seq: * array.length -> int * * Returns the number of elements in self. May be zero. * * [ 1, 2, 3, 4, 5 ].length #=> 5 */ static VALUE rb_ary_length(VALUE ary) { long len = RARRAY_LEN(ary); return LONG2NUM(len); } /* * call-seq: * array.empty? -> true or false * * Returns true if self array contains no elements. * * [].empty? #=> true */ static VALUE rb_ary_empty_p(VALUE ary) { if (RARRAY_LEN(ary) == 0) return Qtrue; return Qfalse; } VALUE rb_ary_dup(VALUE ary) { VALUE dup = rb_ary_new2(RARRAY_LEN(ary)); int is_embed = ARY_EMBED_P(dup); DUPSETUP(dup, ary); if (is_embed) FL_SET_EMBED(dup); MEMCPY(RARRAY_PTR(dup), RARRAY_PTR(ary), VALUE, RARRAY_LEN(ary)); ARY_SET_LEN(dup, RARRAY_LEN(ary)); return dup; } extern VALUE rb_output_fs; static VALUE recursive_join(VALUE ary, VALUE argp, int recur) { VALUE *arg = (VALUE *)argp; if (recur) { return rb_usascii_str_new2("[...]"); } return rb_ary_join(arg[0], arg[1]); } VALUE rb_ary_join(VALUE ary, VALUE sep) { long len = 1, i; int taint = Qfalse; int untrust = Qfalse; VALUE result, tmp; if (RARRAY_LEN(ary) == 0) return rb_str_new(0, 0); if (OBJ_TAINTED(ary) || OBJ_TAINTED(sep)) taint = Qtrue; if (OBJ_UNTRUSTED(ary) || OBJ_UNTRUSTED(sep)) untrust = Qtrue; for (i=0; i 0 && !NIL_P(sep)) rb_str_buf_append(result, sep); rb_str_buf_append(result, tmp); if (OBJ_TAINTED(tmp)) taint = Qtrue; if (OBJ_UNTRUSTED(tmp)) untrust = Qtrue; } if (taint) OBJ_TAINT(result); if (untrust) OBJ_UNTRUST(result); return result; } /* * call-seq: * array.join(sep=$,) -> str * * Returns a string created by converting each element of the array to * a string, separated by sep. * * [ "a", "b", "c" ].join #=> "abc" * [ "a", "b", "c" ].join("-") #=> "a-b-c" */ static VALUE rb_ary_join_m(int argc, VALUE *argv, VALUE ary) { VALUE sep; rb_scan_args(argc, argv, "01", &sep); if (NIL_P(sep)) sep = rb_output_fs; return rb_ary_join(ary, sep); } static VALUE inspect_ary(VALUE ary, VALUE dummy, int recur) { int tainted = OBJ_TAINTED(ary); int untrust = OBJ_UNTRUSTED(ary); long i; VALUE s, str; if (recur) return rb_tainted_str_new2("[...]"); str = rb_str_buf_new2("["); for (i=0; i 0) rb_str_buf_cat2(str, ", "); rb_str_buf_append(str, s); } rb_str_buf_cat2(str, "]"); if (tainted) OBJ_TAINT(str); if (untrust) OBJ_UNTRUST(str); return str; } /* * call-seq: * array.to_s -> string * array.inspect -> string * * Create a printable version of array. */ static VALUE rb_ary_inspect(VALUE ary) { if (RARRAY_LEN(ary) == 0) return rb_usascii_str_new2("[]"); return rb_exec_recursive(inspect_ary, ary, 0); } VALUE rb_ary_to_s(VALUE ary) { return rb_ary_inspect(ary); } /* * call-seq: * array.to_a -> array * * Returns _self_. If called on a subclass of Array, converts * the receiver to an Array object. */ static VALUE rb_ary_to_a(VALUE ary) { if (rb_obj_class(ary) != rb_cArray) { VALUE dup = rb_ary_new2(RARRAY_LEN(ary)); rb_ary_replace(dup, ary); return dup; } return ary; } /* * call-seq: * array.to_ary -> array * * Returns _self_. */ static VALUE rb_ary_to_ary_m(VALUE ary) { return ary; } VALUE rb_ary_reverse(VALUE ary) { VALUE *p1, *p2; VALUE tmp; rb_ary_modify(ary); if (RARRAY_LEN(ary) > 1) { p1 = RARRAY_PTR(ary); p2 = p1 + RARRAY_LEN(ary) - 1; /* points last item */ while (p1 < p2) { tmp = *p1; *p1++ = *p2; *p2-- = tmp; } } return ary; } /* * call-seq: * array.reverse! -> array * * Reverses _self_ in place. * * a = [ "a", "b", "c" ] * a.reverse! #=> ["c", "b", "a"] * a #=> ["c", "b", "a"] */ static VALUE rb_ary_reverse_bang(VALUE ary) { return rb_ary_reverse(ary); } /* * call-seq: * array.reverse -> an_array * * Returns a new array containing self's elements in reverse order. * * [ "a", "b", "c" ].reverse #=> ["c", "b", "a"] * [ 1 ].reverse #=> [1] */ static VALUE rb_ary_reverse_m(VALUE ary) { return rb_ary_reverse(rb_ary_dup(ary)); } struct ary_sort_data { VALUE ary; int opt_methods; int opt_inited; }; enum { sort_opt_Fixnum, sort_opt_String, sort_optimizable_count }; #define STRING_P(s) (TYPE(s) == T_STRING && CLASS_OF(s) == rb_cString) #define SORT_OPTIMIZABLE_BIT(type) (1U << TOKEN_PASTE(sort_opt_,type)) #define SORT_OPTIMIZABLE(data, type) \ ((data->opt_inited & SORT_OPTIMIZABLE_BIT(type)) ? \ (data->opt_methods & SORT_OPTIMIZABLE_BIT(type)) : \ ((data->opt_inited |= SORT_OPTIMIZABLE_BIT(type)), \ rb_method_basic_definition_p(TOKEN_PASTE(rb_c,type), id_cmp) && \ (data->opt_methods |= SORT_OPTIMIZABLE_BIT(type)))) static VALUE sort_reentered(VALUE ary) { if (RBASIC(ary)->klass) { rb_raise(rb_eRuntimeError, "sort reentered"); } return Qnil; } static int sort_1(const void *ap, const void *bp, void *dummy) { struct ary_sort_data *data = dummy; VALUE retval = sort_reentered(data->ary); VALUE a = *(const VALUE *)ap, b = *(const VALUE *)bp; int n; retval = rb_yield_values(2, a, b); n = rb_cmpint(retval, a, b); sort_reentered(data->ary); return n; } static int sort_2(const void *ap, const void *bp, void *dummy) { struct ary_sort_data *data = dummy; VALUE retval = sort_reentered(data->ary); VALUE a = *(const VALUE *)ap, b = *(const VALUE *)bp; int n; if (FIXNUM_P(a) && FIXNUM_P(b) && SORT_OPTIMIZABLE(data, Fixnum)) { if ((long)a > (long)b) return 1; if ((long)a < (long)b) return -1; return 0; } if (STRING_P(a) && STRING_P(b) && SORT_OPTIMIZABLE(data, String)) { return rb_str_cmp(a, b); } retval = rb_funcall(a, id_cmp, 1, b); n = rb_cmpint(retval, a, b); sort_reentered(data->ary); return n; } /* * call-seq: * array.sort! -> array * array.sort! {| a,b | block } -> array * * Sorts _self_. Comparisons for * the sort will be done using the <=> operator or using * an optional code block. The block implements a comparison between * a and b, returning -1, 0, or +1. See also * Enumerable#sort_by. * * a = [ "d", "a", "e", "c", "b" ] * a.sort #=> ["a", "b", "c", "d", "e"] * a.sort {|x,y| y <=> x } #=> ["e", "d", "c", "b", "a"] */ VALUE rb_ary_sort_bang(VALUE ary) { rb_ary_modify(ary); assert(!ARY_SHARED_P(ary)); if (RARRAY_LEN(ary) > 1) { VALUE tmp = ary_make_substitution(ary); /* only ary refers tmp */ struct ary_sort_data data; RBASIC(tmp)->klass = 0; data.ary = tmp; data.opt_methods = 0; data.opt_inited = 0; ruby_qsort(RARRAY_PTR(tmp), RARRAY_LEN(tmp), sizeof(VALUE), rb_block_given_p()?sort_1:sort_2, &data); if (ARY_EMBED_P(tmp)) { assert(ARY_EMBED_P(tmp)); if (ARY_SHARED_P(ary)) { /* ary might be destructively operated in the given block */ rb_ary_unshare(ary); } FL_SET_EMBED(ary); MEMCPY(RARRAY_PTR(ary), ARY_EMBED_PTR(tmp), VALUE, ARY_EMBED_LEN(tmp)); ARY_SET_LEN(ary, ARY_EMBED_LEN(tmp)); } else { assert(!ARY_EMBED_P(tmp)); if (ARY_HEAP_PTR(ary) == ARY_HEAP_PTR(tmp)) { assert(!ARY_EMBED_P(ary)); FL_UNSET_SHARED(ary); ARY_SET_CAPA(ary, ARY_CAPA(tmp)); } else { assert(!ARY_SHARED_P(tmp)); if (ARY_EMBED_P(ary)) { FL_UNSET_EMBED(ary); } else if (ARY_SHARED_P(ary)) { /* ary might be destructively operated in the given block */ rb_ary_unshare(ary); } else { xfree(ARY_HEAP_PTR(ary)); } ARY_SET_PTR(ary, RARRAY_PTR(tmp)); ARY_SET_HEAP_LEN(ary, RARRAY_LEN(tmp)); ARY_SET_CAPA(ary, ARY_CAPA(tmp)); } /* tmp was lost ownership for the ptr */ FL_UNSET(tmp, FL_FREEZE); FL_SET_EMBED(tmp); ARY_SET_EMBED_LEN(tmp, 0); FL_SET(tmp, FL_FREEZE); } /* tmp will be GC'ed. */ RBASIC(tmp)->klass = rb_cArray; } return ary; } /* * call-seq: * array.sort -> an_array * array.sort {| a,b | block } -> an_array * * Returns a new array created by sorting self. Comparisons for * the sort will be done using the <=> operator or using * an optional code block. The block implements a comparison between * a and b, returning -1, 0, or +1. See also * Enumerable#sort_by. * * a = [ "d", "a", "e", "c", "b" ] * a.sort #=> ["a", "b", "c", "d", "e"] * a.sort {|x,y| y <=> x } #=> ["e", "d", "c", "b", "a"] */ VALUE rb_ary_sort(VALUE ary) { ary = rb_ary_dup(ary); rb_ary_sort_bang(ary); return ary; } /* * call-seq: * array.collect {|item| block } -> an_array * array.map {|item| block } -> an_array * * Invokes block once for each element of self. Creates a * new array containing the values returned by the block. * See also Enumerable#collect. * * a = [ "a", "b", "c", "d" ] * a.collect {|x| x + "!" } #=> ["a!", "b!", "c!", "d!"] * a #=> ["a", "b", "c", "d"] */ static VALUE rb_ary_collect(VALUE ary) { long i; VALUE collect; RETURN_ENUMERATOR(ary, 0, 0); collect = rb_ary_new2(RARRAY_LEN(ary)); for (i = 0; i < RARRAY_LEN(ary); i++) { rb_ary_push(collect, rb_yield(RARRAY_PTR(ary)[i])); } return collect; } /* * call-seq: * array.collect! {|item| block } -> array * array.map! {|item| block } -> array * * Invokes the block once for each element of _self_, replacing the * element with the value returned by _block_. * See also Enumerable#collect. * * a = [ "a", "b", "c", "d" ] * a.collect! {|x| x + "!" } * a #=> [ "a!", "b!", "c!", "d!" ] */ static VALUE rb_ary_collect_bang(VALUE ary) { long i; RETURN_ENUMERATOR(ary, 0, 0); rb_ary_modify(ary); for (i = 0; i < RARRAY_LEN(ary); i++) { rb_ary_store(ary, i, rb_yield(RARRAY_PTR(ary)[i])); } return ary; } VALUE rb_get_values_at(VALUE obj, long olen, int argc, VALUE *argv, VALUE (*func) (VALUE, long)) { VALUE result = rb_ary_new2(argc); long beg, len, i, j; for (i=0; i an_array * * Returns an array containing the elements in * _self_ corresponding to the given selector(s). The selectors * may be either integer indices or ranges. * See also Array#select. * * a = %w{ a b c d e f } * a.values_at(1, 3, 5) * a.values_at(1, 3, 5, 7) * a.values_at(-1, -3, -5, -7) * a.values_at(1..3, 2...5) */ static VALUE rb_ary_values_at(int argc, VALUE *argv, VALUE ary) { return rb_get_values_at(ary, RARRAY_LEN(ary), argc, argv, rb_ary_entry); } /* * call-seq: * array.select {|item| block } -> an_array * * Invokes the block passing in successive elements from array, * returning an array containing those elements for which the block * returns a true value (equivalent to Enumerable#select). * * a = %w{ a b c d e f } * a.select {|v| v =~ /[aeiou]/} #=> ["a", "e"] */ static VALUE rb_ary_select(VALUE ary) { VALUE result; long i; RETURN_ENUMERATOR(ary, 0, 0); result = rb_ary_new2(RARRAY_LEN(ary)); for (i = 0; i < RARRAY_LEN(ary); i++) { if (RTEST(rb_yield(RARRAY_PTR(ary)[i]))) { rb_ary_push(result, rb_ary_elt(ary, i)); } } return result; } /* * call-seq: * array.delete(obj) -> obj or nil * array.delete(obj) { block } -> obj or nil * * Deletes items from self that are equal to obj. If * the item is not found, returns nil. If the optional * code block is given, returns the result of block if the item * is not found. * * a = [ "a", "b", "b", "b", "c" ] * a.delete("b") #=> "b" * a #=> ["a", "c"] * a.delete("z") #=> nil * a.delete("z") { "not found" } #=> "not found" */ VALUE rb_ary_delete(VALUE ary, VALUE item) { VALUE v = item; long i1, i2; for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) { VALUE e = RARRAY_PTR(ary)[i1]; if (rb_equal(e, item)) { v = e; continue; } if (i1 != i2) { rb_ary_store(ary, i2, e); } i2++; } if (RARRAY_LEN(ary) == i2) { if (rb_block_given_p()) { return rb_yield(item); } return Qnil; } rb_ary_modify(ary); if (RARRAY_LEN(ary) > i2) { ARY_SET_LEN(ary, i2); if (i2 * 2 < ARY_CAPA(ary) && ARY_CAPA(ary) > ARY_DEFAULT_SIZE) { ary_resize_capa(ary, i2*2); } } return v; } VALUE rb_ary_delete_at(VALUE ary, long pos) { long len = RARRAY_LEN(ary); VALUE del; if (pos >= len) return Qnil; if (pos < 0) { pos += len; if (pos < 0) return Qnil; } rb_ary_modify(ary); del = RARRAY_PTR(ary)[pos]; MEMMOVE(RARRAY_PTR(ary)+pos, RARRAY_PTR(ary)+pos+1, VALUE, RARRAY_LEN(ary)-pos-1); ARY_INCREASE_LEN(ary, -1); return del; } /* * call-seq: * array.delete_at(index) -> obj or nil * * Deletes the element at the specified index, returning that element, * or nil if the index is out of range. See also * Array#slice!. * * a = %w( ant bat cat dog ) * a.delete_at(2) #=> "cat" * a #=> ["ant", "bat", "dog"] * a.delete_at(99) #=> nil */ static VALUE rb_ary_delete_at_m(VALUE ary, VALUE pos) { return rb_ary_delete_at(ary, NUM2LONG(pos)); } /* * call-seq: * array.slice!(index) -> obj or nil * array.slice!(start, length) -> sub_array or nil * array.slice!(range) -> sub_array or nil * * Deletes the element(s) given by an index (optionally with a length) * or by a range. Returns the deleted object, subarray, or * nil if the index is out of range. * * a = [ "a", "b", "c" ] * a.slice!(1) #=> "b" * a #=> ["a", "c"] * a.slice!(-1) #=> "c" * a #=> ["a"] * a.slice!(100) #=> nil * a #=> ["a"] */ static VALUE rb_ary_slice_bang(int argc, VALUE *argv, VALUE ary) { VALUE arg1, arg2; long pos, len, orig_len; rb_ary_modify_check(ary); if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2) { pos = NUM2LONG(arg1); len = NUM2LONG(arg2); delete_pos_len: if (len < 0) return Qnil; orig_len = RARRAY_LEN(ary); if (pos < 0) { pos += orig_len; if (pos < 0) return Qnil; } else if (orig_len < pos) return Qnil; if (orig_len < pos + len) { len = orig_len - pos; } if (len == 0) return rb_ary_new2(0); arg2 = rb_ary_new4(len, RARRAY_PTR(ary)+pos); RBASIC(arg2)->klass = rb_obj_class(ary); rb_ary_splice(ary, pos, len, Qundef); return arg2; } if (!FIXNUM_P(arg1)) { switch (rb_range_beg_len(arg1, &pos, &len, RARRAY_LEN(ary), 0)) { case Qtrue: /* valid range */ goto delete_pos_len; case Qnil: /* invalid range */ return Qnil; default: /* not a range */ break; } } return rb_ary_delete_at(ary, NUM2LONG(arg1)); } /* * call-seq: * array.reject! {|item| block } -> array or nil * * Equivalent to Array#delete_if, deleting elements from * _self_ for which the block evaluates to true, but returns * nil if no changes were made. Also see * Enumerable#reject. */ static VALUE rb_ary_reject_bang(VALUE ary) { long i1, i2; RETURN_ENUMERATOR(ary, 0, 0); rb_ary_modify(ary); for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) { VALUE v = RARRAY_PTR(ary)[i1]; if (RTEST(rb_yield(v))) continue; if (i1 != i2) { rb_ary_store(ary, i2, v); } i2++; } if (RARRAY_LEN(ary) == i2) return Qnil; if (i2 < RARRAY_LEN(ary)) ARY_SET_LEN(ary, i2); return ary; } /* * call-seq: * array.reject {|item| block } -> an_array * * Returns a new array containing the items in _self_ * for which the block is not true. */ static VALUE rb_ary_reject(VALUE ary) { RETURN_ENUMERATOR(ary, 0, 0); ary = rb_ary_dup(ary); rb_ary_reject_bang(ary); return ary; } /* * call-seq: * array.delete_if {|item| block } -> array * * Deletes every element of self for which block evaluates * to true. * * a = [ "a", "b", "c" ] * a.delete_if {|x| x >= "b" } #=> ["a"] */ static VALUE rb_ary_delete_if(VALUE ary) { RETURN_ENUMERATOR(ary, 0, 0); rb_ary_reject_bang(ary); return ary; } static VALUE take_i(VALUE val, VALUE *args, int argc, VALUE *argv) { if (args[1]-- == 0) rb_iter_break(); if (argc > 1) val = rb_ary_new4(argc, argv); rb_ary_push(args[0], val); return Qnil; } static VALUE take_items(VALUE obj, long n) { VALUE result = rb_check_array_type(obj); VALUE args[2]; if (!NIL_P(result)) return rb_ary_subseq(result, 0, n); result = rb_ary_new2(n); args[0] = result; args[1] = (VALUE)n; rb_block_call(obj, rb_intern("each"), 0, 0, take_i, (VALUE)args); return result; } /* * call-seq: * array.zip(arg, ...) -> an_array * array.zip(arg, ...) {| arr | block } -> nil * * Converts any arguments to arrays, then merges elements of * self with corresponding elements from each argument. This * generates a sequence of self.size n-element * arrays, where n is one more that the count of arguments. If * the size of any argument is less than enumObj.size, * nil values are supplied. If a block given, it is * invoked for each output array, otherwise an array of arrays is * returned. * * a = [ 4, 5, 6 ] * b = [ 7, 8, 9 ] * [1,2,3].zip(a, b) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]] * [1,2].zip(a,b) #=> [[1, 4, 7], [2, 5, 8]] * a.zip([1,2],[8]) #=> [[4,1,8], [5,2,nil], [6,nil,nil]] */ static VALUE rb_ary_zip(int argc, VALUE *argv, VALUE ary) { int i, j; long len; VALUE result = Qnil; len = RARRAY_LEN(ary); for (i=0; i an_array * * Assumes that self is an array of arrays and transposes the * rows and columns. * * a = [[1,2], [3,4], [5,6]] * a.transpose #=> [[1, 3, 5], [2, 4, 6]] */ static VALUE rb_ary_transpose(VALUE ary) { long elen = -1, alen, i, j; VALUE tmp, result = 0; alen = RARRAY_LEN(ary); if (alen == 0) return rb_ary_dup(ary); for (i=0; i array * * Replaces the contents of self with the contents of * other_array, truncating or expanding if necessary. * * a = [ "a", "b", "c", "d", "e" ] * a.replace([ "x", "y", "z" ]) #=> ["x", "y", "z"] * a #=> ["x", "y", "z"] */ VALUE rb_ary_replace(VALUE copy, VALUE orig) { orig = to_ary(orig); rb_ary_modify_check(copy); if (copy == orig) return copy; if (RARRAY_LEN(orig) <= RARRAY_EMBED_LEN_MAX) { VALUE *ptr; VALUE shared = 0; if (ARY_OWNS_HEAP_P(copy)) { xfree(RARRAY_PTR(copy)); } else if (ARY_SHARED_P(copy)) { shared = ARY_SHARED(copy); FL_UNSET_SHARED(copy); } FL_SET_EMBED(copy); ptr = RARRAY_PTR(orig); MEMCPY(RARRAY_PTR(copy), ptr, VALUE, RARRAY_LEN(orig)); if (shared) { rb_ary_decrement_share(shared); } ARY_SET_LEN(copy, RARRAY_LEN(orig)); } else { VALUE shared = ary_make_shared(orig); if (ARY_OWNS_HEAP_P(copy)) { xfree(RARRAY_PTR(copy)); } else { rb_ary_unshare_safe(copy); } FL_UNSET_EMBED(copy); ARY_SET_PTR(copy, RARRAY_PTR(orig)); ARY_SET_LEN(copy, RARRAY_LEN(orig)); rb_ary_set_shared(copy, shared); } return copy; } /* * call-seq: * array.clear -> array * * Removes all elements from _self_. * * a = [ "a", "b", "c", "d", "e" ] * a.clear #=> [ ] */ VALUE rb_ary_clear(VALUE ary) { rb_ary_modify(ary); ARY_SET_LEN(ary, 0); if (ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) { ary_resize_capa(ary, ARY_DEFAULT_SIZE * 2); } return ary; } /* * call-seq: * array.fill(obj) -> array * array.fill(obj, start [, length]) -> array * array.fill(obj, range ) -> array * array.fill {|index| block } -> array * array.fill(start [, length] ) {|index| block } -> array * array.fill(range) {|index| block } -> array * * The first three forms set the selected elements of self (which * may be the entire array) to obj. A start of * nil is equivalent to zero. A length of * nil is equivalent to self.length. The last three * forms fill the array with the value of the block. The block is * passed the absolute index of each element to be filled. * * a = [ "a", "b", "c", "d" ] * a.fill("x") #=> ["x", "x", "x", "x"] * a.fill("z", 2, 2) #=> ["x", "x", "z", "z"] * a.fill("y", 0..1) #=> ["y", "y", "z", "z"] * a.fill {|i| i*i} #=> [0, 1, 4, 9] * a.fill(-2) {|i| i*i*i} #=> [0, 1, 8, 27] */ static VALUE rb_ary_fill(int argc, VALUE *argv, VALUE ary) { VALUE item, arg1, arg2; long beg = 0, end = 0, len = 0; VALUE *p, *pend; int block_p = Qfalse; if (rb_block_given_p()) { block_p = Qtrue; rb_scan_args(argc, argv, "02", &arg1, &arg2); argc += 1; /* hackish */ } else { rb_scan_args(argc, argv, "12", &item, &arg1, &arg2); } switch (argc) { case 1: beg = 0; len = RARRAY_LEN(ary); break; case 2: if (rb_range_beg_len(arg1, &beg, &len, RARRAY_LEN(ary), 1)) { break; } /* fall through */ case 3: beg = NIL_P(arg1) ? 0 : NUM2LONG(arg1); if (beg < 0) { beg = RARRAY_LEN(ary) + beg; if (beg < 0) beg = 0; } len = NIL_P(arg2) ? RARRAY_LEN(ary) - beg : NUM2LONG(arg2); break; } rb_ary_modify(ary); if (len < 0) { return ary; } if (beg >= ARY_MAX_SIZE || len > ARY_MAX_SIZE - beg) { rb_raise(rb_eArgError, "argument too big"); } end = beg + len; if (RARRAY_LEN(ary) < end) { if (end >= ARY_CAPA(ary)) { ary_resize_capa(ary, end); } rb_mem_clear(RARRAY_PTR(ary) + RARRAY_LEN(ary), end - RARRAY_LEN(ary)); ARY_SET_LEN(ary, end); } if (block_p) { VALUE v; long i; for (i=beg; i=RARRAY_LEN(ary)) break; RARRAY_PTR(ary)[i] = v; } } else { p = RARRAY_PTR(ary) + beg; pend = p + len; while (p < pend) { *p++ = item; } } return ary; } /* * call-seq: * array + other_array -> an_array * * Concatenation---Returns a new array built by concatenating the * two arrays together to produce a third array. * * [ 1, 2, 3 ] + [ 4, 5 ] #=> [ 1, 2, 3, 4, 5 ] */ VALUE rb_ary_plus(VALUE x, VALUE y) { VALUE z; long len; y = to_ary(y); len = RARRAY_LEN(x) + RARRAY_LEN(y); z = rb_ary_new2(len); MEMCPY(RARRAY_PTR(z), RARRAY_PTR(x), VALUE, RARRAY_LEN(x)); MEMCPY(RARRAY_PTR(z) + RARRAY_LEN(x), RARRAY_PTR(y), VALUE, RARRAY_LEN(y)); ARY_SET_LEN(z, len); return z; } /* * call-seq: * array.concat(other_array) -> array * * Appends the elements in other_array to _self_. * * [ "a", "b" ].concat( ["c", "d"] ) #=> [ "a", "b", "c", "d" ] */ VALUE rb_ary_concat(VALUE x, VALUE y) { y = to_ary(y); if (RARRAY_LEN(y) > 0) { rb_ary_splice(x, RARRAY_LEN(x), 0, y); } return x; } /* * call-seq: * array * int -> an_array * array * str -> a_string * * Repetition---With a String argument, equivalent to * self.join(str). Otherwise, returns a new array * built by concatenating the _int_ copies of _self_. * * * [ 1, 2, 3 ] * 3 #=> [ 1, 2, 3, 1, 2, 3, 1, 2, 3 ] * [ 1, 2, 3 ] * "," #=> "1,2,3" * */ static VALUE rb_ary_times(VALUE ary, VALUE times) { VALUE ary2, tmp; long i, len; tmp = rb_check_string_type(times); if (!NIL_P(tmp)) { return rb_ary_join(ary, tmp); } len = NUM2LONG(times); if (len == 0) { ary2 = ary_new(rb_obj_class(ary), 0); goto out; } if (len < 0) { rb_raise(rb_eArgError, "negative argument"); } if (ARY_MAX_SIZE/len < RARRAY_LEN(ary)) { rb_raise(rb_eArgError, "argument too big"); } len *= RARRAY_LEN(ary); ary2 = ary_new(rb_obj_class(ary), len); ARY_SET_LEN(ary2, len); for (i=0; i an_array or nil * * Searches through an array whose elements are also arrays * comparing _obj_ with the first element of each contained array * using obj.==. * Returns the first contained array that matches (that * is, the first associated array), * or +nil+ if no match is found. * See also Array#rassoc. * * s1 = [ "colors", "red", "blue", "green" ] * s2 = [ "letters", "a", "b", "c" ] * s3 = "foo" * a = [ s1, s2, s3 ] * a.assoc("letters") #=> [ "letters", "a", "b", "c" ] * a.assoc("foo") #=> nil */ VALUE rb_ary_assoc(VALUE ary, VALUE key) { long i; VALUE v; for (i = 0; i < RARRAY_LEN(ary); ++i) { v = rb_check_array_type(RARRAY_PTR(ary)[i]); if (!NIL_P(v) && RARRAY_LEN(v) > 0 && rb_equal(RARRAY_PTR(v)[0], key)) return v; } return Qnil; } /* * call-seq: * array.rassoc(obj) -> an_array or nil * * Searches through the array whose elements are also arrays. Compares * _obj_ with the second element of each contained array using * ==. Returns the first contained array that matches. See * also Array#assoc. * * a = [ [ 1, "one"], [2, "two"], [3, "three"], ["ii", "two"] ] * a.rassoc("two") #=> [2, "two"] * a.rassoc("four") #=> nil */ VALUE rb_ary_rassoc(VALUE ary, VALUE value) { long i; VALUE v; for (i = 0; i < RARRAY_LEN(ary); ++i) { v = RARRAY_PTR(ary)[i]; if (TYPE(v) == T_ARRAY && RARRAY_LEN(v) > 1 && rb_equal(RARRAY_PTR(v)[1], value)) return v; } return Qnil; } static VALUE recursive_equal(VALUE ary1, VALUE ary2, int recur) { long i; if (recur) return Qtrue; /* Subtle! */ for (i=0; i bool * * Equality---Two arrays are equal if they contain the same number * of elements and if each element is equal to (according to * Object.==) the corresponding element in the other array. * * [ "a", "c" ] == [ "a", "c", 7 ] #=> false * [ "a", "c", 7 ] == [ "a", "c", 7 ] #=> true * [ "a", "c", 7 ] == [ "a", "d", "f" ] #=> false * */ static VALUE rb_ary_equal(VALUE ary1, VALUE ary2) { if (ary1 == ary2) return Qtrue; if (TYPE(ary2) != T_ARRAY) { if (!rb_respond_to(ary2, rb_intern("to_ary"))) { return Qfalse; } return rb_equal(ary2, ary1); } if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse; return rb_exec_recursive_paired(recursive_equal, ary1, ary2, ary2); } static VALUE recursive_eql(VALUE ary1, VALUE ary2, int recur) { long i; if (recur) return Qtrue; /* Subtle! */ for (i=0; i true or false * * Returns true if _array_ and _other_ are the same object, * or are both arrays with the same content. */ static VALUE rb_ary_eql(VALUE ary1, VALUE ary2) { if (ary1 == ary2) return Qtrue; if (TYPE(ary2) != T_ARRAY) return Qfalse; if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse; return rb_exec_recursive_paired(recursive_eql, ary1, ary2, ary2); } static VALUE recursive_hash(VALUE ary, VALUE dummy, int recur) { long i, h; VALUE n; if (recur) { return LONG2FIX(0); } h = RARRAY_LEN(ary); for (i=0; i fixnum * * Compute a hash-code for this array. Two arrays with the same content * will have the same hash code (and will compare using eql?). */ static VALUE rb_ary_hash(VALUE ary) { return rb_exec_recursive(recursive_hash, ary, 0); } /* * call-seq: * array.include?(obj) -> true or false * * Returns true if the given object is present in * self (that is, if any object == anObject), * false otherwise. * * a = [ "a", "b", "c" ] * a.include?("b") #=> true * a.include?("z") #=> false */ VALUE rb_ary_includes(VALUE ary, VALUE item) { long i; for (i=0; i RARRAY_LEN(ary2)) { len = RARRAY_LEN(ary2); } for (i=0; i other_array -> -1, 0, +1 * * Comparison---Returns an integer (-1, 0, * or +1) if this array is less than, equal to, or greater than * other_array. Each object in each array is compared * (using <=>). If any value isn't * equal, then that inequality is the return value. If all the * values found are equal, then the return is based on a * comparison of the array lengths. Thus, two arrays are * ``equal'' according to Array#<=> if and only if they have * the same length and the value of each element is equal to the * value of the corresponding element in the other array. * * [ "a", "a", "c" ] <=> [ "a", "b", "c" ] #=> -1 * [ 1, 2, 3, 4, 5, 6 ] <=> [ 1, 2 ] #=> +1 * */ VALUE rb_ary_cmp(VALUE ary1, VALUE ary2) { long len; VALUE v; ary2 = to_ary(ary2); if (ary1 == ary2) return INT2FIX(0); v = rb_exec_recursive_paired(recursive_cmp, ary1, ary2, ary2); if (v != Qundef) return v; len = RARRAY_LEN(ary1) - RARRAY_LEN(ary2); if (len == 0) return INT2FIX(0); if (len > 0) return INT2FIX(1); return INT2FIX(-1); } static VALUE ary_make_hash(VALUE ary1, VALUE ary2) { VALUE hash = rb_hash_new(); long i; for (i=0; i an_array * * Array Difference---Returns a new array that is a copy of * the original array, removing any items that also appear in * other_array. (If you need set-like behavior, see the * library class Set.) * * [ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ] #=> [ 3, 3, 5 ] */ static VALUE rb_ary_diff(VALUE ary1, VALUE ary2) { VALUE ary3; volatile VALUE hash; long i; hash = ary_make_hash(to_ary(ary2), 0); ary3 = rb_ary_new(); for (i=0; i [ 1, 3 ] */ static VALUE rb_ary_and(VALUE ary1, VALUE ary2) { VALUE hash, ary3, v, vv; long i; ary2 = to_ary(ary2); ary3 = rb_ary_new2(RARRAY_LEN(ary1) < RARRAY_LEN(ary2) ? RARRAY_LEN(ary1) : RARRAY_LEN(ary2)); hash = ary_make_hash(ary2, 0); if (RHASH_EMPTY_P(hash)) return ary3; for (i=0; i an_array * * Set Union---Returns a new array by joining this array with * other_array, removing duplicates. * * [ "a", "b", "c" ] | [ "c", "d", "a" ] * #=> [ "a", "b", "c", "d" ] */ static VALUE rb_ary_or(VALUE ary1, VALUE ary2) { VALUE hash, ary3; VALUE v, vv; long i; ary2 = to_ary(ary2); ary3 = rb_ary_new2(RARRAY_LEN(ary1)+RARRAY_LEN(ary2)); hash = ary_make_hash(ary1, ary2); for (i=0; i array or nil * * Removes duplicate elements from _self_. * Returns nil if no changes are made (that is, no * duplicates are found). * * a = [ "a", "a", "b", "b", "c" ] * a.uniq! #=> ["a", "b", "c"] * b = [ "a", "b", "c" ] * b.uniq! #=> nil */ static VALUE rb_ary_uniq_bang(VALUE ary) { VALUE hash, v, vv; long i, j; hash = ary_make_hash(ary, 0); if (RARRAY_LEN(ary) == RHASH_SIZE(hash)) { return Qnil; } for (i=j=0; i an_array * * Returns a new array by removing duplicate values in self. * * a = [ "a", "a", "b", "b", "c" ] * a.uniq #=> ["a", "b", "c"] */ static VALUE rb_ary_uniq(VALUE ary) { ary = rb_ary_dup(ary); rb_ary_uniq_bang(ary); return ary; } /* * call-seq: * array.compact! -> array or nil * * Removes +nil+ elements from array. * Returns +nil+ if no changes were made. * * [ "a", nil, "b", nil, "c" ].compact! #=> [ "a", "b", "c" ] * [ "a", "b", "c" ].compact! #=> nil */ static VALUE rb_ary_compact_bang(VALUE ary) { VALUE *p, *t, *end; long n; rb_ary_modify(ary); p = t = RARRAY_PTR(ary); end = p + RARRAY_LEN(ary); while (t < end) { if (NIL_P(*t)) t++; else *p++ = *t++; } n = p - RARRAY_PTR(ary); if (RARRAY_LEN(ary) == n) { return Qnil; } ARY_SET_LEN(ary, n); if (n * 2 < ARY_CAPA(ary) && ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) { ary_resize_capa(ary, n * 2); } return ary; } /* * call-seq: * array.compact -> an_array * * Returns a copy of _self_ with all +nil+ elements removed. * * [ "a", nil, "b", nil, "c", nil ].compact * #=> [ "a", "b", "c" ] */ static VALUE rb_ary_compact(VALUE ary) { ary = rb_ary_dup(ary); rb_ary_compact_bang(ary); return ary; } /* * call-seq: * array.count -> int * array.count(obj) -> int * array.count { |item| block } -> int * * Returns the number of elements. If an argument is given, counts * the number of elements which equals to obj. If a block is * given, counts the number of elements yielding a true value. * * ary = [1, 2, 4, 2] * ary.count # => 4 * ary.count(2) # => 2 * ary.count{|x|x%2==0} # => 3 * */ static VALUE rb_ary_count(int argc, VALUE *argv, VALUE ary) { long n = 0; if (argc == 0) { VALUE *p, *pend; if (!rb_block_given_p()) return LONG2NUM(RARRAY_LEN(ary)); for (p = RARRAY_PTR(ary), pend = p + RARRAY_LEN(ary); p < pend; p++) { if (RTEST(rb_yield(*p))) n++; } } else { VALUE obj, *p, *pend; rb_scan_args(argc, argv, "1", &obj); if (rb_block_given_p()) { rb_warn("given block not used"); } for (p = RARRAY_PTR(ary), pend = p + RARRAY_LEN(ary); p < pend; p++) { if (rb_equal(*p, obj)) n++; } } return LONG2NUM(n); } static VALUE flatten(VALUE ary, int level, int *modified) { long i = 0; VALUE stack, result, tmp, elt; st_table *memo; st_data_t id; stack = ary_new(0, ARY_DEFAULT_SIZE); result = ary_new(0, RARRAY_LEN(ary)); memo = st_init_numtable(); st_insert(memo, (st_data_t)ary, (st_data_t)Qtrue); *modified = 0; while (1) { while (i < RARRAY_LEN(ary)) { elt = RARRAY_PTR(ary)[i++]; tmp = rb_check_array_type(elt); if (RBASIC(result)->klass) { rb_raise(rb_eRuntimeError, "flatten reentered"); } if (NIL_P(tmp) || (level >= 0 && RARRAY_LEN(stack) / 2 >= level)) { rb_ary_push(result, elt); } else { *modified = 1; id = (st_data_t)tmp; if (st_lookup(memo, id, 0)) { st_free_table(memo); rb_raise(rb_eArgError, "tried to flatten recursive array"); } st_insert(memo, id, (st_data_t)Qtrue); rb_ary_push(stack, ary); rb_ary_push(stack, LONG2NUM(i)); ary = tmp; i = 0; } } if (RARRAY_LEN(stack) == 0) { break; } id = (st_data_t)ary; st_delete(memo, &id, 0); tmp = rb_ary_pop(stack); i = NUM2LONG(tmp); ary = rb_ary_pop(stack); } st_free_table(memo); RBASIC(result)->klass = rb_class_of(ary); return result; } /* * call-seq: * array.flatten! -> array or nil * array.flatten!(level) -> array or nil * * Flattens _self_ in place. * Returns nil if no modifications were made (i.e., * array contains no subarrays.) If the optional level * argument determines the level of recursion to flatten. * * a = [ 1, 2, [3, [4, 5] ] ] * a.flatten! #=> [1, 2, 3, 4, 5] * a.flatten! #=> nil * a #=> [1, 2, 3, 4, 5] * a = [ 1, 2, [3, [4, 5] ] ] * a.flatten!(1) #=> [1, 2, 3, [4, 5]] */ static VALUE rb_ary_flatten_bang(int argc, VALUE *argv, VALUE ary) { int mod = 0, level = -1; VALUE result, lv; rb_scan_args(argc, argv, "01", &lv); if (!NIL_P(lv)) level = NUM2INT(lv); if (level == 0) return Qnil; result = flatten(ary, level, &mod); if (mod == 0) return Qnil; rb_ary_replace(ary, result); return ary; } /* * call-seq: * array.flatten -> an_array * array.flatten(level) -> an_array * * Returns a new array that is a one-dimensional flattening of this * array (recursively). That is, for every element that is an array, * extract its elements into the new array. If the optional * level argument determines the level of recursion to flatten. * * s = [ 1, 2, 3 ] #=> [1, 2, 3] * t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]] * a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10] * a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] * a = [ 1, 2, [3, [4, 5] ] ] * a.flatten(1) #=> [1, 2, 3, [4, 5]] */ static VALUE rb_ary_flatten(int argc, VALUE *argv, VALUE ary) { int mod = 0, level = -1; VALUE result, lv; rb_scan_args(argc, argv, "01", &lv); if (!NIL_P(lv)) level = NUM2INT(lv); if (level == 0) return ary_make_shared_copy(ary); result = flatten(ary, level, &mod); OBJ_INFECT(result, ary); return result; } /* * call-seq: * array.shuffle! -> array * * Shuffles elements in _self_ in place. */ static VALUE rb_ary_shuffle_bang(VALUE ary) { long i = RARRAY_LEN(ary); rb_ary_modify(ary); while (i) { long j = rb_genrand_real()*i; VALUE tmp = RARRAY_PTR(ary)[--i]; RARRAY_PTR(ary)[i] = RARRAY_PTR(ary)[j]; RARRAY_PTR(ary)[j] = tmp; } return ary; } /* * call-seq: * array.shuffle -> an_array * * Returns a new array with elements of this array shuffled. * * a = [ 1, 2, 3 ] #=> [1, 2, 3] * a.shuffle #=> [2, 3, 1] */ static VALUE rb_ary_shuffle(VALUE ary) { ary = rb_ary_dup(ary); rb_ary_shuffle_bang(ary); return ary; } /* * call-seq: * array.sample -> obj * array.sample(n) -> an_array * * Choose a random element, or the random +n+ elements, from the array. * If the array is empty, the first form returns nil, and the * second form returns an empty array. * */ static VALUE rb_ary_sample(int argc, VALUE *argv, VALUE ary) { VALUE nv, result, *ptr; long n, len, i, j, k, idx[10]; len = RARRAY_LEN(ary); if (argc == 0) { if (len == 0) return Qnil; i = len == 1 ? 0 : rb_genrand_real()*len; return RARRAY_PTR(ary)[i]; } rb_scan_args(argc, argv, "1", &nv); n = NUM2LONG(nv); if (n < 0) rb_raise(rb_eArgError, "negative sample number"); ptr = RARRAY_PTR(ary); len = RARRAY_LEN(ary); if (n > len) n = len; switch (n) { case 0: return rb_ary_new2(0); case 1: return rb_ary_new4(1, &ptr[(long)(rb_genrand_real()*len)]); case 2: i = rb_genrand_real()*len; j = rb_genrand_real()*(len-1); if (j >= i) j++; return rb_ary_new3(2, ptr[i], ptr[j]); case 3: i = rb_genrand_real()*len; j = rb_genrand_real()*(len-1); k = rb_genrand_real()*(len-2); { long l = j, g = i; if (j >= i) l = i, g = ++j; if (k >= l && (++k >= g)) ++k; } return rb_ary_new3(3, ptr[i], ptr[j], ptr[k]); } if (n < sizeof(idx)/sizeof(idx[0])) { long sorted[sizeof(idx)/sizeof(idx[0])]; sorted[0] = idx[0] = rb_genrand_real()*len; for (i=1; iblock for each element repeatedly _n_ times or * forever if none or nil is given. If a non-positive number is * given or the array is empty, does nothing. Returns nil if the * loop has finished without getting interrupted. * * a = ["a", "b", "c"] * a.cycle {|x| puts x } # print, a, b, c, a, b, c,.. forever. * a.cycle(2) {|x| puts x } # print, a, b, c, a, b, c. * */ static VALUE rb_ary_cycle(int argc, VALUE *argv, VALUE ary) { long n, i; VALUE nv = Qnil; rb_scan_args(argc, argv, "01", &nv); RETURN_ENUMERATOR(ary, argc, argv); if (NIL_P(nv)) { n = -1; } else { n = NUM2LONG(nv); if (n <= 0) return Qnil; } while (RARRAY_LEN(ary) > 0 && (n < 0 || 0 < n--)) { for (i=0; i array * ary.permutation -> enumerator * ary.permutation(n) { |p| block } -> array * ary.permutation(n) -> enumerator * * When invoked with a block, yield all permutations of length n * of the elements of ary, then return the array itself. * If n is not specified, yield all permutations of all elements. * The implementation makes no guarantees about the order in which * the permutations are yielded. * * When invoked without a block, return an enumerator object instead. * * Examples: * * a = [1, 2, 3] * a.permutation.to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] * a.permutation(1).to_a #=> [[1],[2],[3]] * a.permutation(2).to_a #=> [[1,2],[1,3],[2,1],[2,3],[3,1],[3,2]] * a.permutation(3).to_a #=> [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] * a.permutation(0).to_a #=> [[]] # one permutation of length 0 * a.permutation(4).to_a #=> [] # no permutations of length 4 */ static VALUE rb_ary_permutation(int argc, VALUE *argv, VALUE ary) { VALUE num; long r, n, i; n = RARRAY_LEN(ary); /* Array length */ RETURN_ENUMERATOR(ary, argc, argv); /* Return enumerator if no block */ rb_scan_args(argc, argv, "01", &num); r = NIL_P(num) ? n : NUM2LONG(num); /* Permutation size from argument */ if (r < 0 || n < r) { /* no permutations: yield nothing */ } else if (r == 0) { /* exactly one permutation: the zero-length array */ rb_yield(rb_ary_new2(0)); } else if (r == 1) { /* this is a special, easy case */ for (i = 0; i < RARRAY_LEN(ary); i++) { rb_yield(rb_ary_new3(1, RARRAY_PTR(ary)[i])); } } else { /* this is the general case */ volatile VALUE t0 = tmpbuf(n,sizeof(long)); long *p = (long*)RSTRING_PTR(t0); volatile VALUE t1 = tmpbuf(n,sizeof(int)); int *used = (int*)RSTRING_PTR(t1); VALUE ary0 = ary_make_substitution(ary); /* private defensive copy of ary */ RBASIC(ary0)->klass = 0; for (i = 0; i < n; i++) used[i] = 0; /* initialize array */ permute0(n, r, p, 0, used, ary0); /* compute and yield permutations */ RB_GC_GUARD(t0); RB_GC_GUARD(t1); RBASIC(ary0)->klass = rb_cArray; } return ary; } static long combi_len(long n, long k) { long i, val = 1; if (k*2 > n) k = n-k; if (k == 0) return 1; if (k < 0) return 0; val = 1; for (i=1; i <= k; i++,n--) { long m = val; val *= n; if (val < m) { rb_raise(rb_eRangeError, "too big for combination"); } val /= i; } return val; } /* * call-seq: * ary.combination(n) { |c| block } -> ary * ary.combination(n) -> enumerator * * When invoked with a block, yields all combinations of length n * of elements from ary and then returns ary itself. * The implementation makes no guarantees about the order in which * the combinations are yielded. * * When invoked without a block, returns an enumerator object instead. * * Examples: * * a = [1, 2, 3, 4] * a.combination(1).to_a #=> [[1],[2],[3],[4]] * a.combination(2).to_a #=> [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]] * a.combination(3).to_a #=> [[1,2,3],[1,2,4],[1,3,4],[2,3,4]] * a.combination(4).to_a #=> [[1,2,3,4]] * a.combination(0).to_a #=> [[]] # one combination of length 0 * a.combination(5).to_a #=> [] # no combinations of length 5 * */ static VALUE rb_ary_combination(VALUE ary, VALUE num) { long n, i, len; n = NUM2LONG(num); RETURN_ENUMERATOR(ary, 1, &num); len = RARRAY_LEN(ary); if (n < 0 || len < n) { /* yield nothing */ } else if (n == 0) { rb_yield(rb_ary_new2(0)); } else if (n == 1) { for (i = 0; i < len; i++) { rb_yield(rb_ary_new3(1, RARRAY_PTR(ary)[i])); } } else { volatile VALUE t0 = tmpbuf(n+1, sizeof(long)); long *stack = (long*)RSTRING_PTR(t0); long nlen = combi_len(len, n); volatile VALUE cc = rb_ary_new2(n); VALUE *chosen = RARRAY_PTR(cc); long lev = 0; RBASIC(cc)->klass = 0; MEMZERO(stack, long, n); stack[0] = -1; for (i = 0; i < nlen; i++) { chosen[lev] = RARRAY_PTR(ary)[stack[lev+1]]; for (lev++; lev < n; lev++) { chosen[lev] = RARRAY_PTR(ary)[stack[lev+1] = stack[lev]+1]; } rb_yield(rb_ary_new4(n, chosen)); do { stack[lev--]++; } while (lev && (stack[lev+1]+n == len+lev+1)); } } return ary; } /* * call-seq: * ary.product(other_ary, ...) * * Returns an array of all combinations of elements from all arrays. * The length of the returned array is the product of the length * of ary and the argument arrays * * [1,2,3].product([4,5]) # => [[1,4],[1,5],[2,4],[2,5],[3,4],[3,5]] * [1,2].product([1,2]) # => [[1,1],[1,2],[2,1],[2,2]] * [1,2].product([3,4],[5,6]) # => [[1,3,5],[1,3,6],[1,4,5],[1,4,6], * # [2,3,5],[2,3,6],[2,4,5],[2,4,6]] * [1,2].product() # => [[1],[2]] * [1,2].product([]) # => [] */ static VALUE rb_ary_product(int argc, VALUE *argv, VALUE ary) { int n = argc+1; /* How many arrays we're operating on */ volatile VALUE t0 = tmpbuf(n, sizeof(VALUE)); volatile VALUE t1 = tmpbuf(n, sizeof(int)); VALUE *arrays = (VALUE*)RSTRING_PTR(t0); /* The arrays we're computing the product of */ int *counters = (int*)RSTRING_PTR(t1); /* The current position in each one */ VALUE result; /* The array we'll be returning */ long i,j; long resultlen = 1; RBASIC(t0)->klass = 0; RBASIC(t1)->klass = 0; /* initialize the arrays of arrays */ arrays[0] = ary; for (i = 1; i < n; i++) arrays[i] = to_ary(argv[i-1]); /* initialize the counters for the arrays */ for (i = 0; i < n; i++) counters[i] = 0; /* Compute the length of the result array; return [] if any is empty */ for (i = 0; i < n; i++) { long k = RARRAY_LEN(arrays[i]), l = resultlen; if (k == 0) return rb_ary_new2(0); resultlen *= k; if (resultlen < k || resultlen < l || resultlen / k != l) { rb_raise(rb_eRangeError, "too big to product"); } } /* Otherwise, allocate and fill in an array of results */ result = rb_ary_new2(resultlen); for (i = 0; i < resultlen; i++) { int m; /* fill in one subarray */ VALUE subarray = rb_ary_new2(n); for (j = 0; j < n; j++) { rb_ary_push(subarray, rb_ary_entry(arrays[j], counters[j])); } /* put it on the result array */ rb_ary_push(result, subarray); /* * Increment the last counter. If it overflows, reset to 0 * and increment the one before it. */ m = n-1; counters[m]++; while (m > 0 && counters[m] == RARRAY_LEN(arrays[m])) { counters[m] = 0; m--; counters[m]++; } } return result; } /* * call-seq: * ary.take(n) => array * * Returns first n elements from ary. * * a = [1, 2, 3, 4, 5, 0] * a.take(3) # => [1, 2, 3] * */ static VALUE rb_ary_take(VALUE obj, VALUE n) { long len = NUM2LONG(n); if (len < 0) { rb_raise(rb_eArgError, "attempt to take negative size"); } return rb_ary_subseq(obj, 0, len); } /* * call-seq: * ary.take_while {|arr| block } => array * * Passes elements to the block until the block returns nil or false, * then stops iterating and returns an array of all prior elements. * * a = [1, 2, 3, 4, 5, 0] * a.take_while {|i| i < 3 } # => [1, 2] * */ static VALUE rb_ary_take_while(VALUE ary) { long i; RETURN_ENUMERATOR(ary, 0, 0); for (i = 0; i < RARRAY_LEN(ary); i++) { if (!RTEST(rb_yield(RARRAY_PTR(ary)[i]))) break; } return rb_ary_take(ary, LONG2FIX(i)); } /* * call-seq: * ary.drop(n) => array * * Drops first n elements from ary, and returns rest elements * in an array. * * a = [1, 2, 3, 4, 5, 0] * a.drop(3) # => [4, 5, 0] * */ static VALUE rb_ary_drop(VALUE ary, VALUE n) { VALUE result; long pos = NUM2LONG(n); if (pos < 0) { rb_raise(rb_eArgError, "attempt to drop negative size"); } result = rb_ary_subseq(ary, pos, RARRAY_LEN(ary)); if (result == Qnil) result = rb_ary_new(); return result; } /* * call-seq: * ary.drop_while {|arr| block } => array * * Drops elements up to, but not including, the first element for * which the block returns nil or false and returns an array * containing the remaining elements. * * a = [1, 2, 3, 4, 5, 0] * a.drop_while {|i| i < 3 } # => [3, 4, 5, 0] * */ static VALUE rb_ary_drop_while(VALUE ary) { long i; RETURN_ENUMERATOR(ary, 0, 0); for (i = 0; i < RARRAY_LEN(ary); i++) { if (!RTEST(rb_yield(RARRAY_PTR(ary)[i]))) break; } return rb_ary_drop(ary, LONG2FIX(i)); } /* Arrays are ordered, integer-indexed collections of any object. * Array indexing starts at 0, as in C or Java. A negative index is * assumed to be relative to the end of the array---that is, an index of -1 * indicates the last element of the array, -2 is the next to last * element in the array, and so on. */ void Init_Array(void) { #undef rb_intern #define rb_intern(str) rb_intern_const(str) rb_cArray = rb_define_class("Array", rb_cObject); rb_include_module(rb_cArray, rb_mEnumerable); rb_define_alloc_func(rb_cArray, ary_alloc); rb_define_singleton_method(rb_cArray, "[]", rb_ary_s_create, -1); rb_define_singleton_method(rb_cArray, "try_convert", rb_ary_s_try_convert, 1); rb_define_method(rb_cArray, "initialize", rb_ary_initialize, -1); rb_define_method(rb_cArray, "initialize_copy", rb_ary_replace, 1); rb_define_method(rb_cArray, "to_s", rb_ary_inspect, 0); rb_define_method(rb_cArray, "inspect", rb_ary_inspect, 0); rb_define_method(rb_cArray, "to_a", rb_ary_to_a, 0); rb_define_method(rb_cArray, "to_ary", rb_ary_to_ary_m, 0); rb_define_method(rb_cArray, "frozen?", rb_ary_frozen_p, 0); rb_define_method(rb_cArray, "==", rb_ary_equal, 1); rb_define_method(rb_cArray, "eql?", rb_ary_eql, 1); rb_define_method(rb_cArray, "hash", rb_ary_hash, 0); rb_define_method(rb_cArray, "[]", rb_ary_aref, -1); rb_define_method(rb_cArray, "[]=", rb_ary_aset, -1); rb_define_method(rb_cArray, "at", rb_ary_at, 1); rb_define_method(rb_cArray, "fetch", rb_ary_fetch, -1); rb_define_method(rb_cArray, "first", rb_ary_first, -1); rb_define_method(rb_cArray, "last", rb_ary_last, -1); rb_define_method(rb_cArray, "concat", rb_ary_concat, 1); rb_define_method(rb_cArray, "<<", rb_ary_push, 1); rb_define_method(rb_cArray, "push", rb_ary_push_m, -1); rb_define_method(rb_cArray, "pop", rb_ary_pop_m, -1); rb_define_method(rb_cArray, "shift", rb_ary_shift_m, -1); rb_define_method(rb_cArray, "unshift", rb_ary_unshift_m, -1); rb_define_method(rb_cArray, "insert", rb_ary_insert, -1); rb_define_method(rb_cArray, "each", rb_ary_each, 0); rb_define_method(rb_cArray, "each_index", rb_ary_each_index, 0); rb_define_method(rb_cArray, "reverse_each", rb_ary_reverse_each, 0); rb_define_method(rb_cArray, "length", rb_ary_length, 0); rb_define_alias(rb_cArray, "size", "length"); rb_define_method(rb_cArray, "empty?", rb_ary_empty_p, 0); rb_define_method(rb_cArray, "find_index", rb_ary_index, -1); rb_define_method(rb_cArray, "index", rb_ary_index, -1); rb_define_method(rb_cArray, "rindex", rb_ary_rindex, -1); rb_define_method(rb_cArray, "join", rb_ary_join_m, -1); rb_define_method(rb_cArray, "reverse", rb_ary_reverse_m, 0); rb_define_method(rb_cArray, "reverse!", rb_ary_reverse_bang, 0); rb_define_method(rb_cArray, "sort", rb_ary_sort, 0); rb_define_method(rb_cArray, "sort!", rb_ary_sort_bang, 0); rb_define_method(rb_cArray, "collect", rb_ary_collect, 0); rb_define_method(rb_cArray, "collect!", rb_ary_collect_bang, 0); rb_define_method(rb_cArray, "map", rb_ary_collect, 0); rb_define_method(rb_cArray, "map!", rb_ary_collect_bang, 0); rb_define_method(rb_cArray, "select", rb_ary_select, 0); rb_define_method(rb_cArray, "values_at", rb_ary_values_at, -1); rb_define_method(rb_cArray, "delete", rb_ary_delete, 1); rb_define_method(rb_cArray, "delete_at", rb_ary_delete_at_m, 1); rb_define_method(rb_cArray, "delete_if", rb_ary_delete_if, 0); rb_define_method(rb_cArray, "reject", rb_ary_reject, 0); rb_define_method(rb_cArray, "reject!", rb_ary_reject_bang, 0); rb_define_method(rb_cArray, "zip", rb_ary_zip, -1); rb_define_method(rb_cArray, "transpose", rb_ary_transpose, 0); rb_define_method(rb_cArray, "replace", rb_ary_replace, 1); rb_define_method(rb_cArray, "clear", rb_ary_clear, 0); rb_define_method(rb_cArray, "fill", rb_ary_fill, -1); rb_define_method(rb_cArray, "include?", rb_ary_includes, 1); rb_define_method(rb_cArray, "<=>", rb_ary_cmp, 1); rb_define_method(rb_cArray, "slice", rb_ary_aref, -1); rb_define_method(rb_cArray, "slice!", rb_ary_slice_bang, -1); rb_define_method(rb_cArray, "assoc", rb_ary_assoc, 1); rb_define_method(rb_cArray, "rassoc", rb_ary_rassoc, 1); rb_define_method(rb_cArray, "+", rb_ary_plus, 1); rb_define_method(rb_cArray, "*", rb_ary_times, 1); rb_define_method(rb_cArray, "-", rb_ary_diff, 1); rb_define_method(rb_cArray, "&", rb_ary_and, 1); rb_define_method(rb_cArray, "|", rb_ary_or, 1); rb_define_method(rb_cArray, "uniq", rb_ary_uniq, 0); rb_define_method(rb_cArray, "uniq!", rb_ary_uniq_bang, 0); rb_define_method(rb_cArray, "compact", rb_ary_compact, 0); rb_define_method(rb_cArray, "compact!", rb_ary_compact_bang, 0); rb_define_method(rb_cArray, "flatten", rb_ary_flatten, -1); rb_define_method(rb_cArray, "flatten!", rb_ary_flatten_bang, -1); rb_define_method(rb_cArray, "count", rb_ary_count, -1); rb_define_method(rb_cArray, "shuffle!", rb_ary_shuffle_bang, 0); rb_define_method(rb_cArray, "shuffle", rb_ary_shuffle, 0); rb_define_method(rb_cArray, "sample", rb_ary_sample, -1); rb_define_method(rb_cArray, "cycle", rb_ary_cycle, -1); rb_define_method(rb_cArray, "permutation", rb_ary_permutation, -1); rb_define_method(rb_cArray, "combination", rb_ary_combination, 1); rb_define_method(rb_cArray, "product", rb_ary_product, -1); rb_define_method(rb_cArray, "take", rb_ary_take, 1); rb_define_method(rb_cArray, "take_while", rb_ary_take_while, 0); rb_define_method(rb_cArray, "drop", rb_ary_drop, 1); rb_define_method(rb_cArray, "drop_while", rb_ary_drop_while, 0); id_cmp = rb_intern("<=>"); } yard-0.8.7.3/spec/parser/examples/override.c.txt0000644000004100000410000002511112261240652021523 0ustar www-datawww-data#include #include #include /* * Document-class: GMP::Z * * GMP Multiple Precision Integer. * * Instances of this class can store variables of the type mpz_t. This class * also contains many methods that act as the functions for mpz_t variables, * as well as a few methods that attempt to make this library more Ruby-ish. */ /********************************************************************** * Macros * **********************************************************************/ /* * DEFUN_INT2INT defines two functions. The first takes a GMP::Z as * self, calls mpz_fname on the contained mpz_t, whose arguments are * exactly (0) the return argument and (1) self. The second is the same * destructive method. */ #define DEFUN_INT2INT(fname,mpz_fname) \ static VALUE r_gmpz_##fname(VALUE self) \ { \ MP_INT *self_val, *res_val; \ VALUE res; \ mpz_get_struct(self, self_val); \ mpz_make_struct_init(res, res_val); \ mpz_fname(res_val, self_val); \ return res; \ } \ \ static VALUE r_gmpz_##fname##_self(VALUE self) \ { \ MP_INT *self_val; \ mpz_get_struct(self, self_val); \ mpz_fname(self_val, self_val); \ return self; \ } /********************************************************************** * Integer Arithmetic * **********************************************************************/ /* * call-seq: * a + b * * Adds _a_ to _b_. _b_ must be an instance of one of: * * GMP::Z * * Fixnum * * GMP::Q * * GMP::F * * Bignum */ VALUE r_gmpz_add(VALUE self, VALUE arg) { MP_INT *self_val, *arg_val, *res_val; VALUE res; mpz_get_struct(self,self_val); if (GMPZ_P(arg)) { mpz_get_struct(arg,arg_val); mpz_make_struct_init(res, res_val); mpz_add(res_val, self_val, arg_val); } else if (FIXNUM_P(arg)) { mpz_make_struct_init(res, res_val); if (FIX2NUM(arg) > 0) mpz_add_ui(res_val, self_val, FIX2NUM(arg)); else mpz_sub_ui(res_val, self_val, -FIX2NUM(arg)); } else if (GMPQ_P(arg)) { return r_gmpq_add(arg, self); } else if (GMPF_P(arg)) { #ifndef MPFR return r_gmpf_add(arg, self); #else return rb_funcall(arg, rb_intern("+"), 1, self); #endif } else if (BIGNUM_P(arg)) { mpz_make_struct_init(res, res_val); mpz_init(res_val); mpz_set_bignum(res_val, arg); mpz_add(res_val, res_val, self_val); } else { typeerror(ZQFXB); } return res; } /* * call-seq: * a.add!(_b_) * * Adds _a_ to _b_ in-place, setting _a_ to the sum. _b_ must be an instance of one of: * * GMP::Z * * Fixnum * * GMP::Q * * GMP::F * * Bignum */ VALUE r_gmpz_add_self(VALUE self, VALUE arg) { MP_INT *self_val, *arg_val; mpz_get_struct(self,self_val); if (GMPZ_P(arg)) { mpz_get_struct(arg,arg_val); mpz_add(self_val, self_val, arg_val); } else if (FIXNUM_P(arg)) { if (FIX2NUM(arg) > 0) mpz_add_ui(self_val, self_val, FIX2NUM(arg)); else mpz_sub_ui(self_val, self_val, -FIX2NUM(arg)); } else if (BIGNUM_P(arg)) { mpz_temp_from_bignum(arg_val, arg); mpz_add(self_val, self_val, arg_val); mpz_temp_free(arg_val); } else { typeerror(ZXB); } return Qnil; } /* * call-seq: * a - b * * Subtracts _b_ from _a_. _b_ must be an instance of one of: * * GMP::Z * * Fixnum * * GMP::Q * * GMP::F * * Bignum */ VALUE r_gmpz_sub(VALUE self, VALUE arg) { MP_RAT *res_val_q, *arg_val_q; MP_INT *self_val, *arg_val, *res_val; MP_FLOAT *arg_val_f, *res_val_f; VALUE res; unsigned long prec; mpz_get_struct(self,self_val); if (GMPZ_P(arg)) { mpz_make_struct_init(res, res_val); mpz_get_struct(arg,arg_val); mpz_sub (res_val, self_val, arg_val); } else if (FIXNUM_P(arg)) { mpz_make_struct_init(res, res_val); if (FIX2NUM(arg) > 0) mpz_sub_ui (res_val, self_val, FIX2NUM(arg)); else mpz_add_ui (res_val, self_val, -FIX2NUM(arg)); } else if (GMPQ_P(arg)) { mpq_make_struct_init(res, res_val_q); mpq_get_struct(arg,arg_val_q); mpz_set (mpq_denref(res_val_q), mpq_denref(arg_val_q)); mpz_mul (mpq_numref(res_val_q), mpq_denref(arg_val_q), self_val); mpz_sub (mpq_numref(res_val_q), mpq_numref(res_val_q), mpq_numref(arg_val_q)); } else if (GMPF_P(arg)) { mpf_get_struct_prec (arg, arg_val_f, prec); mpf_make_struct_init(res, res_val_f, prec); mpf_set_z (res_val_f, self_val); mpf_sub (res_val_f, res_val_f, arg_val_f); } else if (BIGNUM_P(arg)) { mpz_make_struct_init(res, res_val); mpz_set_bignum (res_val, arg); mpz_sub (res_val, self_val, res_val); } else { typeerror (ZQFXB); } return res; } /* * call-seq: * a.sub!(b) * * Subtracts _b_ from _a_ in-place, setting _a_ to the difference. _b_ must be an * instance of one of: * * GMP::Z * * Fixnum * * GMP::Q * * GMP::F * * Bignum */ VALUE r_gmpz_sub_self(VALUE self, VALUE arg) { MP_INT *self_val, *arg_val; mpz_get_struct(self,self_val); if (GMPZ_P(arg)) { mpz_get_struct(arg, arg_val); mpz_sub (self_val, self_val, arg_val); } else if (FIXNUM_P(arg)) { if (FIX2NUM(arg) > 0) mpz_sub_ui (self_val, self_val, FIX2NUM(arg)); else mpz_add_ui (self_val, self_val, -FIX2NUM(arg)); } else if (BIGNUM_P(arg)) { mpz_temp_from_bignum(arg_val, arg); mpz_sub (self_val, self_val, arg_val); mpz_temp_free (arg_val); } else { typeerror (ZXB); } return Qnil; } /* * call-seq: * a * b * * Multiplies _a_ with _b_. _a_ must be an instance of one of * * GMP::Z * * Fixnum * * GMP::Q * * GMP::F * * Bignum */ VALUE r_gmpz_mul(VALUE self, VALUE arg) { MP_INT *self_val, *arg_val, *res_val; VALUE res; mpz_get_struct(self,self_val); if (GMPZ_P(arg)) { mpz_make_struct_init(res, res_val); mpz_get_struct(arg,arg_val); mpz_mul(res_val, self_val, arg_val); } else if (FIXNUM_P(arg)) { mpz_make_struct_init(res, res_val); mpz_mul_si(res_val, self_val, FIX2NUM(arg)); } else if (GMPQ_P(arg)) { return r_gmpq_mul(arg, self); } else if (GMPF_P(arg)) { #ifndef MPFR return r_gmpf_mul(arg, self); #else return rb_funcall(arg, rb_intern("*"), 1, self); #endif } else if (BIGNUM_P(arg)) { mpz_make_struct_init(res, res_val); mpz_set_bignum(res_val, arg); mpz_mul(res_val, res_val, self_val); } else { typeerror(ZQFXB); } return res; } /* * call-seq: * a.addmul!(b, c) * * @since 0.4.17 * * Sets _a_ to _a_ plus _b_ times _c_. _b_ and _c_ must each be an instance of one of * * GMP::Z * * Fixnum * * Bignum */ VALUE r_gmpz_addmul_self(VALUE self, VALUE b, VALUE c) { MP_INT *self_val, *b_val, *c_val; int free_b_val = 0; if (GMPZ_P(b)) { mpz_get_struct(b, b_val); } else if (FIXNUM_P(b)) { mpz_temp_alloc(b_val); mpz_init_set_si(b_val, FIX2NUM(b)); free_b_val = 1; } else if (BIGNUM_P(b)) { mpz_temp_from_bignum(b_val, b); free_b_val = 1; } else { typeerror_as(ZXB, "addend"); } mpz_get_struct(self, self_val); if (GMPZ_P(c)) { mpz_get_struct(c, c_val); mpz_addmul(self_val, b_val, c_val); } else if (FIXNUM_P(c)) { if (FIX2NUM(c) < 0) { if (free_b_val) { mpz_temp_free(b_val); } rb_raise(rb_eRangeError, "multiplicand (Fixnum) must be nonnegative"); } mpz_addmul_ui(self_val, b_val, FIX2NUM(c)); } else if (BIGNUM_P(c)) { mpz_temp_from_bignum(c_val, c); mpz_addmul(self_val, b_val, c_val); mpz_temp_free(c_val); } else { if (free_b_val) mpz_temp_free(b_val); typeerror_as(ZXB, "multiplicand"); } if (free_b_val) mpz_temp_free(b_val); return self; } /* * Document-method: neg * * call-seq: * a.neg * -a * * Returns -_a_. */ /* * Document-method: neg! * * call-seq: * a.neg! * * Sets _a_ to -_a_. */ DEFUN_INT2INT(neg, mpz_neg) /* * Document-method: abs * * call-seq: * a.abs * * Returns the absolute value of _a_. */ /* * Document-method: abs! * * call-seq: * a.abs! * * Sets _a_ to its absolute value. */ DEFUN_INT2INT(abs, mpz_abs) /********************************************************************** * Integer Roots * **********************************************************************/ /* * Document-method: sqrt * * call-seq: * a.sqrt * * Returns the truncated integer part of the square root of _a_. */ /* * Document-method: sqrt! * * call-seq: * a.sqrt! * * Sets _a_ to the truncated integer part of its square root. */ DEFUN_INT2INT(sqrt, mpz_sqrt) /* * call-seq: * a.sqrtrem #=> s, r * * Returns the truncated integer part of the square root of _a_ as _s_ and the remainder * a - s * s as _r_, which will be zero if _a_ is a perfect square. */ static VALUE r_gmpz_sqrtrem(VALUE self) { MP_INT *self_val, *sqrt_val, *rem_val; VALUE sqrt, rem; mpz_get_struct(self, self_val); mpz_make_struct_init(sqrt, sqrt_val); mpz_make_struct_init(rem, rem_val); mpz_sqrtrem(sqrt_val, rem_val, self_val); return rb_assoc_new(sqrt, rem); } /********************************************************************** * Init function * **********************************************************************/ void init_gmpz() { mGMP = rb_define_module("GMP"); rb_define_module_function(mGMP, "Z", r_gmpmod_z, -1); cGMP_Z = rb_define_class_under(mGMP, "Z", rb_cInteger); // Integer Arithmetic rb_define_method(cGMP_Z, "+", r_gmpz_add, 1); rb_define_method(cGMP_Z, "add!", r_gmpz_add_self, 1); rb_define_method(cGMP_Z, "-", r_gmpz_sub, 1); rb_define_method(cGMP_Z, "sub!", r_gmpz_sub_self, 1); rb_define_method(cGMP_Z, "*", r_gmpz_mul, 1); rb_define_method(cGMP_Z, "addmul!", r_gmpz_addmul_self, 2); rb_define_method(cGMP_Z, "neg", r_gmpz_neg, 0); rb_define_method(cGMP_Z, "neg!", r_gmpz_neg_self, 0); rb_define_method(cGMP_Z, "-@", r_gmpz_neg, 0); rb_define_method(cGMP_Z, "abs", r_gmpz_abs, 0); rb_define_method(cGMP_Z, "abs!", r_gmpz_abs_self, 0); // Integer Roots rb_define_method(cGMP_Z, "root", r_gmpz_root, 1); rb_define_method(cGMP_Z, "sqrt", r_gmpz_sqrt, 0); rb_define_method(cGMP_Z, "sqrt!", r_gmpz_sqrt_self, 0); rb_define_method(cGMP_Z, "sqrtrem", r_gmpz_sqrtrem, 0); } yard-0.8.7.3/spec/parser/examples/parse_in_order_002.rb.txt0000644000004100000410000000002312261240652023434 0ustar www-datawww-datamodule MyModule endyard-0.8.7.3/spec/parser/tag_parsing_spec.rb0000644000004100000410000000077212261240652020747 0ustar www-datawww-datarequire File.join(File.dirname(__FILE__), '..', 'spec_helper') describe YARD::Parser, "tag handling" do before { parse_file :tag_handler_001, __FILE__ } it "should know the list of all available tags" do P("Foo#foo").tags.should include(P("Foo#foo").tag(:api)) end it "should know the text of tags on a method" do P("Foo#foo").tag(:api).text.should == "public" end it "should return true when asked whether a tag exists" do P("Foo#foo").has_tag?(:api).should == true end end yard-0.8.7.3/spec/parser/source_parser_spec.rb0000644000004100000410000005723212261240652021330 0ustar www-datawww-datarequire File.join(File.dirname(__FILE__), '..', 'spec_helper') class MyParser < Parser::Base; end shared_examples_for "parser type registration" do after do Parser::SourceParser.parser_types.delete(:my_parser) Parser::SourceParser.parser_type_extensions.delete(:my_parser) end end describe YARD::Parser::SourceParser do before do Registry.clear end def parse_list(*list) files = list.map do |v| filename, source = *v File.stub!(:read_binary).with(filename).and_return(source) filename end Parser::SourceParser.send(:parse_in_order, *files) end def before_list(&block) Parser::SourceParser.before_parse_list(&block) end def after_list(&block) Parser::SourceParser.after_parse_list(&block) end def before_file(&block) Parser::SourceParser.before_parse_file(&block) end def after_file(&block) Parser::SourceParser.after_parse_file(&block) end describe '.before_parse_list' do before do Parser::SourceParser.before_parse_list_callbacks.clear Parser::SourceParser.after_parse_list_callbacks.clear end it "should handle basic callback support" do before_list do |files, globals| files.should == ['foo.rb', 'bar.rb'] globals.should == OpenStruct.new end parse_list ['foo.rb', 'foo!'], ['bar.rb', 'class Foo; end'] Registry.at('Foo').should_not be_nil end it "should support multiple callbacks" do checks = [] before_list { checks << :one } before_list { checks << :two } parse_list ['file.rb', ''], ['file2.rb', ''], ['file3.rb', 'class Foo; end'] Registry.at('Foo').should_not be_nil checks.should == [:one, :two] end it "should cancel parsing if it returns false" do checks = [] before_list { checks << :one } before_list { false } before_list { checks << :three } parse_list ['file.rb', ''], ['file2.rb', ''], ['file3.rb', 'class Foo; end'] Registry.at('Foo').should be_nil checks.should == [:one] end it "should not cancel on nil" do checks = [] before_list { checks << :one } before_list { nil } before_list { checks << :two } parse_list ['file.rb', ''], ['file2.rb', ''], ['file3.rb', 'class Foo; end'] Registry.at('Foo').should_not be_nil checks.should == [:one, :two] end it "should pass in globals" do before_list {|f,g| g.x = 1 } before_list {|f,g| g.x += 1 } before_list {|f,g| g.x += 1 } after_list {|f,g| g.x.should == 3 } parse_list ['file.rb', ''], ['file2.rb', ''], ['file3.rb', 'class Foo; end'] Registry.at('Foo').should_not be_nil end end describe '.after_parse_list' do before do Parser::SourceParser.before_parse_list_callbacks.clear Parser::SourceParser.after_parse_list_callbacks.clear end it "should handle basic callback support and maintain files/globals" do before_list do |f,g| g.foo = :bar end after_list do |files, globals| files.should == ['foo.rb', 'bar.rb'] globals.foo.should == :bar end parse_list ['foo.rb', 'foo!'], ['bar.rb', 'class Foo; end'] Registry.at('Foo').should_not be_nil end it "should support multiple callbacks" do checks = [] after_list { checks << :one } after_list { checks << :two } parse_list ['file.rb', ''], ['file2.rb', ''], ['file3.rb', 'class Foo; end'] Registry.at('Foo').should_not be_nil checks.should == [:one, :two] end it "should not cancel parsing if it returns false" do checks = [] after_list { checks << :one } after_list { false } after_list { checks << :three } parse_list ['file.rb', ''], ['file2.rb', ''], ['file3.rb', 'class Foo; end'] Registry.at('Foo').should_not be_nil checks.should == [:one, :three] end end describe '.before_parse_file' do before do Parser::SourceParser.before_parse_file_callbacks.clear Parser::SourceParser.after_parse_file_callbacks.clear end it "should handle basic callback support" do before_file do |parser| parser.contents.should == 'class Foo; end' parser.file.should =~ /(foo|bar)\.rb/ end parse_list ['foo.rb', 'class Foo; end'], ['bar.rb', 'class Foo; end'] Registry.at('Foo').should_not be_nil end it "should support multiple callbacks" do checks = [] before_file { checks << :one } before_file { checks << :two } parse_list ['file.rb', ''], ['file2.rb', ''], ['file3.rb', 'class Foo; end'] Registry.at('Foo').should_not be_nil checks.should == [:one, :two, :one, :two, :one, :two] end it "should cancel parsing if it returns false" do checks = [] before_file { checks << :one } before_file { false } before_file { checks << :three } parse_list ['file.rb', ''], ['file2.rb', ''], ['file3.rb', 'class Foo; end'] Registry.at('Foo').should be_nil checks.should == [:one, :one, :one] end it "should not cancel on nil" do checks = [] before_file { checks << :one } before_file { nil } before_file { checks << :two } parse_list ['file.rb', ''], ['file2.rb', ''], ['file3.rb', 'class Foo; end'] Registry.at('Foo').should_not be_nil checks.should == [:one, :two, :one, :two, :one, :two] end end describe '.after_parse_file' do before do Parser::SourceParser.before_parse_file_callbacks.clear Parser::SourceParser.after_parse_file_callbacks.clear end it "should handle basic callback support" do after_file do |parser| parser.contents.should == 'class Foo; end' parser.file.should =~ /(foo|bar)\.rb/ end parse_list ['foo.rb', 'class Foo; end'], ['bar.rb', 'class Foo; end'] Registry.at('Foo').should_not be_nil end it "should support multiple callbacks" do checks = [] after_file { checks << :one } after_file { checks << :two } parse_list ['file.rb', ''], ['file2.rb', ''], ['file3.rb', 'class Foo; end'] Registry.at('Foo').should_not be_nil checks.should == [:one, :two, :one, :two, :one, :two] end it "should not cancel parsing if it returns false" do checks = [] after_file { checks << :one } after_file { false } after_file { checks << :three } parse_list ['file.rb', ''], ['file2.rb', ''], ['file3.rb', 'class Foo; end'] Registry.at('Foo').should_not be_nil checks.should == [:one, :three, :one, :three, :one, :three] end end describe '.register_parser_type' do it_should_behave_like "parser type registration" it "should register a subclass of Parser::Base" do parser = mock(:parser) parser.should_receive(:parse) MyParser.should_receive(:new).with('content', '(stdin)').and_return(parser) Parser::SourceParser.register_parser_type(:my_parser, MyParser, 'myparser') Parser::SourceParser.parse_string('content', :my_parser) end it "should require class to be a subclass of Parser::Base" do lambda { Parser::SourceParser.register_parser_type(:my_parser, String) }.should raise_error(ArgumentError) lambda { Parser::SourceParser.register_parser_type(:my_parser, Parser::Base) }.should raise_error(ArgumentError) end end describe '.parser_type_for_extension' do it_should_behave_like "parser type registration" it "should find an extension in a registered array of extensions" do Parser::SourceParser.register_parser_type(:my_parser, MyParser, ['a', 'b', 'd']) Parser::SourceParser.parser_type_for_extension('a').should == :my_parser Parser::SourceParser.parser_type_for_extension('b').should == :my_parser Parser::SourceParser.parser_type_for_extension('d').should == :my_parser Parser::SourceParser.parser_type_for_extension('c').should_not == :my_parser end it "should find an extension in a Regexp" do Parser::SourceParser.register_parser_type(:my_parser, MyParser, /abc$/) Parser::SourceParser.parser_type_for_extension('dabc').should == :my_parser Parser::SourceParser.parser_type_for_extension('dabcd').should_not == :my_parser end it "should find an extension in a list of Regexps" do Parser::SourceParser.register_parser_type(:my_parser, MyParser, [/ab$/, /abc$/]) Parser::SourceParser.parser_type_for_extension('dabc').should == :my_parser Parser::SourceParser.parser_type_for_extension('dabcd').should_not == :my_parser end it "should find an extension in a String" do Parser::SourceParser.register_parser_type(:my_parser, MyParser, "abc") Parser::SourceParser.parser_type_for_extension('abc').should == :my_parser Parser::SourceParser.parser_type_for_extension('abcd').should_not == :my_parser end end describe '#parse_string' do it "should parse basic Ruby code" do YARD.parse_string(<<-eof) module Hello class Hi # Docstring # Docstring2 def me; "VALUE" end end end eof Registry.at(:Hello).should_not == nil Registry.at("Hello::Hi#me").should_not == nil Registry.at("Hello::Hi#me").docstring.should == "Docstring\nDocstring2" Registry.at("Hello::Hi#me").docstring.line_range.should == (3..4) end it "should parse Ruby code with metaclasses" do YARD.parse_string(<<-eof) module Hello class Hi class < false, '##' => true}.each do |hash, expected| YARD.parse_string "#{hash}\n# Foo bar\nclass Foo; end" Registry.at(:Foo).docstring.hash_flag.should == expected end end it "should remove shebang from initial file comments" do YARD.parse_string "#!/bin/ruby\n# this is a comment\nclass Foo; end" Registry.at(:Foo).docstring.should == "this is a comment" end it "should remove encoding line from initial file comments" do YARD.parse_string "# encoding: utf-8\n# this is a comment\nclass Foo; end" Registry.at(:Foo).docstring.should == "this is a comment" end it "should add macros on any object" do YARD.parse_string <<-eof # @!macro [new] foo # This is a macro # @return [String] the string class Foo # @!macro foo def foo; end end eof macro = CodeObjects::MacroObject.find('foo') macro.macro_data.should == "This is a macro\n@return [String] the string" Registry.at('Foo').docstring.to_raw.should == macro.macro_data Registry.at('Foo#foo').docstring.to_raw.should == macro.macro_data end it "should allow directives parsed on lone comments" do YARD.parse_string(<<-eof) class Foo # @!method foo(a = "hello") # @!scope class # @!visibility private # @param [String] a the name of the foo # @return [Symbol] the symbolized foo # @!method bar(value) end eof foo = Registry.at('Foo.foo') bar = Registry.at('Foo#bar') foo.should_not be_nil foo.visibility.should == :private foo.tag(:param).name.should == 'a' foo.tag(:return).types.should == ['Symbol'] bar.should_not be_nil bar.signature.should == 'def bar(value)' end it "should parse lone comments at end of blocks" do YARD.parse_string(<<-eof) class Foo none # @!method foo(a = "hello") end eof foo = Registry.at('Foo#foo') foo.should_not be_nil foo.signature.should == 'def foo(a = "hello")' end it "should handle lone comment with no code" do YARD.parse_string '# @!method foo(a = "hello")' foo = Registry.at('#foo') foo.should_not be_nil foo.signature.should == 'def foo(a = "hello")' end it "should handle non-ASCII encoding in heredoc" do YARD.parse_string <<-eof # encoding: utf-8 heredoc <<-ending foo\u{ffe2} bar. ending # Hello \u{ffe2} world class Foo < Bar attr_accessor :foo end eof Registry.at('Foo').superclass.should == P('Bar') end end describe '#parse' do it "should parse a basic Ruby file" do parse_file :example1, __FILE__ Registry.at(:Hello).should_not == nil Registry.at("Hello::Hi#me").should_not == nil Registry.at("Hello::Hi#me").docstring.should == "Docstring" end it "should parse a set of file globs" do Dir.should_receive(:[]).with('lib/**/*.rb').and_return([]) YARD.parse('lib/**/*.rb') end it "should parse a set of absolute paths" do Dir.should_not_receive(:[]) File.should_receive(:file?).with('/path/to/file').and_return(true) File.should_receive(:read_binary).with('/path/to/file').and_return("") YARD.parse('/path/to/file') end it "should clean paths before parsing" do File.should_receive(:open).and_return("") parser = Parser::SourceParser.new(:ruby, true) parser.parse('a//b//c') parser.file.should == 'a/b/c' end it "should parse files with '*' in them as globs and others as absolute paths" do Dir.should_receive(:[]).with('*.rb').and_return(['a.rb', 'b.rb']) File.should_receive(:file?).with('/path/to/file').and_return(true) File.should_receive(:file?).with('a.rb').and_return(true) File.should_receive(:file?).with('b.rb').and_return(true) File.should_receive(:read_binary).with('/path/to/file').and_return("") File.should_receive(:read_binary).with('a.rb').and_return("") File.should_receive(:read_binary).with('b.rb').and_return("") YARD.parse ['/path/to/file', '*.rb'] end it "should convert directories into globs" do Dir.should_receive(:[]).with('foo/**/*.{rb,c}').and_return(['foo/a.rb', 'foo/bar/b.rb']) File.should_receive(:directory?).with('foo').and_return(true) File.should_receive(:file?).with('foo/a.rb').and_return(true) File.should_receive(:file?).with('foo/bar/b.rb').and_return(true) File.should_receive(:read_binary).with('foo/a.rb').and_return("") File.should_receive(:read_binary).with('foo/bar/b.rb').and_return("") YARD.parse ['foo'] end it "should use Registry.checksums cache if file is cached" do data = 'DATA' hash = Registry.checksum_for(data) cmock = mock(:cmock) cmock.should_receive(:[]).with('foo/bar').and_return(hash) Registry.should_receive(:checksums).and_return(cmock) File.should_receive(:file?).with('foo/bar').and_return(true) File.should_receive(:read_binary).with('foo/bar').and_return(data) YARD.parse('foo/bar') end it "should support excluded paths" do File.should_receive(:file?).with('foo/bar').and_return(true) File.should_receive(:file?).with('foo/baz').and_return(true) File.should_not_receive(:read_binary) YARD.parse(["foo/bar", "foo/baz"], ["foo", /baz$/]) end it "should convert file contents to proper encoding if coding line is present" do valid = [] valid << "# encoding: sjis" valid << "# encoding: utf-8" valid << "# xxxxxencoding: sjis" valid << "# xxxxxencoding: sjis xxxxxx" valid << "# ENCODING: sjis" valid << "#coDiNG: sjis" valid << "# -*- coding: sjis -*-" valid << "# -*- coding: utf-8; indent-tabs-mode: nil" valid << "### coding: sjis" valid << "# encoding=sjis" valid << "# encoding:sjis" valid << "# encoding = sjis" valid << "# encoding == sjis" valid << "# encoding : sjis" valid << "# encoding :: sjis" valid << "#!/bin/shebang\n# encoding: sjis" valid << "#!/bin/shebang\r\n# coding: sjis" invalid = [] invalid << "#\n# encoding: sjis" invalid << "#!/bin/shebang\n#\n# encoding: sjis" invalid << "# !/bin/shebang\n# encoding: sjis" {:should => valid, :should_not => invalid}.each do |msg, list| list.each do |src| Registry.clear parser = Parser::SourceParser.new File.should_receive(:read_binary).with('tmpfile').and_return(src) result = parser.parse("tmpfile") if HAVE_RIPPER && YARD.ruby19? if msg == :should_not default_encoding = 'UTF-8' result.enumerator[0].source.encoding.to_s.should eq(default_encoding) else ['Shift_JIS', 'Windows-31J', 'UTF-8'].send(msg, include( result.enumerator[0].source.encoding.to_s)) end end result.encoding_line.send(msg) == src.split("\n").last end end end it "should convert C file contents to proper encoding if coding line is present" do valid = [] valid << "/* coding: utf-8 */" valid << "/* -*- coding: utf-8; c-file-style: \"ruby\" -*- */" valid << "// coding: utf-8" valid << "// -*- coding: utf-8; c-file-style: \"ruby\" -*-" invalid = [] {:should => valid, :should_not => invalid}.each do |msg, list| list.each do |src| Registry.clear parser = Parser::SourceParser.new File.should_receive(:read_binary).with('tmpfile.c').and_return(src) result = parser.parse("tmpfile.c") content = result.instance_variable_get("@content") ['UTF-8'].send(msg, include(content.encoding.to_s)) end end end if YARD.ruby19? Parser::SourceParser::ENCODING_BYTE_ORDER_MARKS.each do |encoding, bom| it "should understand #{encoding.upcase} BOM" do parser = Parser::SourceParser.new src = bom + "class FooBar; end".force_encoding('binary') src.force_encoding('binary') File.should_receive(:read_binary).with('tmpfile').and_return(src) result = parser.parse('tmpfile') Registry.all(:class).first.path.should == "FooBar" result.enumerator[0].source.encoding.to_s.downcase.should == encoding end end if HAVE_RIPPER && YARD.ruby19? end describe '#parse_in_order' do def in_order_parse(*files) paths = files.map {|f| File.join(File.dirname(__FILE__), 'examples', f.to_s + '.rb.txt') } YARD::Parser::SourceParser.parse(paths, [], Logger::DEBUG) end it "should attempt to parse files in order" do log.enter_level(Logger::DEBUG) do msgs = [] log.should_receive(:debug) {|m| msgs << m }.at_least(:once) log.stub(:<<) in_order_parse 'parse_in_order_001', 'parse_in_order_002' msgs[1].should =~ /Parsing .+parse_in_order_001.+/ msgs[2].should =~ /Missing object MyModule/ msgs[3].should =~ /Parsing .+parse_in_order_002.+/ msgs[4].should =~ /Re-processing .+parse_in_order_001.+/ end end it "should attempt to order files by length for globs (process toplevel files first)" do files = %w(a a/b a/b/c) files.each do |file| File.should_receive(:file?).with(file).and_return(true) File.should_receive(:read_binary).with(file).ordered.and_return('') end Dir.should_receive(:[]).with('a/**/*').and_return(files.reverse) YARD.parse 'a/**/*' end it "should allow overriding of length sorting when single file is presented" do files = %w(a/b/c a a/b) files.each do |file| File.should_receive(:file?).with(file).at_least(1).times.and_return(true) File.should_receive(:read_binary).with(file).ordered.and_return('') end Dir.should_receive(:[]).with('a/**/*').and_return(files.reverse) YARD.parse ['a/b/c', 'a/**/*'] end end describe '#parse_statements' do before do Registry.clear end it "should display a warning for invalid parser type" do log.should_receive(:warn).with(/unrecognized file/) log.should_receive(:backtrace) YARD::Parser::SourceParser.parse_string("int main() { }", :d) end if HAVE_RIPPER it "should display a warning for a syntax error (with new parser)" do log.should_receive(:warn).with(/Syntax error in/) log.should_receive(:backtrace) YARD::Parser::SourceParser.parse_string("%!!!", :ruby) end end it "should handle groups" do YARD.parse_string <<-eof class A # @group Group Name def foo; end def foo2; end # @endgroup def bar; end # @group Group 2 def baz; end end eof Registry.at('A').groups.should == ['Group Name', 'Group 2'] Registry.at('A#bar').group.should be_nil Registry.at('A#foo').group.should == "Group Name" Registry.at('A#foo2').group.should == "Group Name" Registry.at('A#baz').group.should == "Group 2" end it 'handles multi-line class/module references' do YARD.parse_string <<-eof class A:: B::C; end eof Registry.all.should == [P('A::B::C')] end it 'handles sclass definitions of multi-line class/module references' do YARD.parse_string <<-eof class << A:: B::C def foo; end end eof Registry.all.size.should == 2 Registry.at('A::B::C').should_not be_nil Registry.at('A::B::C.foo').should_not be_nil end it 'handles lone comment blocks at the end of a namespace' do YARD.parse_string <<-eof module A class B def c; end # @!method d end end eof Registry.at('A#d').should be_nil Registry.at('A::B#d').should_not be_nil end it 'supports keyword arguments' do YARD.parse_string 'def foo(a: 1, b: 2, **kwargs) end' args = [['a:', '1'], ['b:', '2'], ['**kwargs', nil]] Registry.at('#foo').parameters.should eq(args) end if YARD.ruby2? end end yard-0.8.7.3/spec/parser/c_parser_spec.rb0000644000004100000410000001265412261240652020251 0ustar www-datawww-datarequire File.join(File.dirname(__FILE__), '..', 'spec_helper') describe YARD::Parser::C::CParser do describe '#parse' do def parse(contents) Registry.clear YARD.parse_string(contents, :c) end describe 'Array class' do before(:all) do file = File.join(File.dirname(__FILE__), 'examples', 'array.c.txt') parse(File.read(file)) end it "should parse Array class" do obj = YARD::Registry.at('Array') obj.should_not be_nil obj.docstring.should_not be_blank end it "should parse method" do obj = YARD::Registry.at('Array#initialize') obj.docstring.should_not be_blank obj.tags(:overload).size.should > 1 end end describe 'Source located in extra files' do before(:all) do @multifile = File.join(File.dirname(__FILE__), 'examples', 'multifile.c.txt') @extrafile = File.join(File.dirname(__FILE__), 'examples', 'extrafile.c.txt') @contents = File.read(@multifile) end it "should look for methods in extra files (if 'in' comment is found)" do extra_contents = File.read(@extrafile) File.should_receive(:read).with('extra.c').and_return(extra_contents) parse(@contents) Registry.at('Multifile#extra').docstring.should == 'foo' end it "should stop searching for extra source file gracefully if file is not found" do File.should_receive(:read).with('extra.c').and_raise(Errno::ENOENT) log.should_receive(:warn).with("Missing source file `extra.c' when parsing Multifile#extra") parse(@contents) Registry.at('Multifile#extra').docstring.should == '' end it "should differentiate between a struct and a pointer to a struct retval" do parse(@contents) Registry.at('Multifile#hello_mars').docstring.should == 'Hello Mars' end end describe 'Foo class' do it 'should not include comments in docstring source' do parse <<-eof /* * Hello world */ VALUE foo(VALUE x) { int value = x; } void Init_Foo() { rb_define_method(rb_cFoo, "foo", foo, 1); } eof Registry.at('Foo#foo').source.gsub(/\s\s+/, ' ').should == "VALUE foo(VALUE x) { int value = x;\n}" end end describe 'Constant' do it 'should not truncate docstring' do parse <<-eof #define MSK_DEADBEEF 0xdeadbeef void Init_Mask(void) { rb_cMask = rb_define_class("Mask", rb_cObject); /* 0xdeadbeef: This constant is frequently used to indicate a * software crash or deadlock in embedded systems. */ rb_define_const(rb_cMask, "DEADBEEF", INT2FIX(MSK_DEADBEEF)); } eof constant = Registry.at('Mask::DEADBEEF') constant.value.should == '0xdeadbeef' constant.docstring.should == "This constant is frequently used to indicate a\nsoftware crash or deadlock in embedded systems." end end describe 'Macros' do it "should handle param## inside of macros" do thr = Thread.new do parse <<-eof void Init_gobject_gparamspecs(void) { VALUE cParamSpec = GTYPE2CLASS(G_TYPE_PARAM); VALUE c; #define DEF_NUMERIC_PSPEC_METHODS(c, typename) \ G_STMT_START {\ rbg_define_method(c, "initialize", typename##_initialize, 7); \ rbg_define_method(c, "minimum", typename##_minimum, 0); \ rbg_define_method(c, "maximum", typename##_maximum, 0); \ rbg_define_method(c, "range", typename##_range, 0); \ } G_STMT_END #if 0 rbg_define_method(c, "default_value", typename##_default_value, 0); \ rb_define_alias(c, "default", "default_value"); \ #endif c = G_DEF_CLASS(G_TYPE_PARAM_CHAR, "Char", cParamSpec); DEF_NUMERIC_PSPEC_METHODS(c, char); eof end thr.join(5) if thr.alive? fail "Did not parse in time" thr.kill end end end end describe 'Override comments' do before(:all) do Registry.clear override_file = File.join(File.dirname(__FILE__), 'examples', 'override.c.txt') @override_parser = YARD.parse_string(File.read(override_file), :c) end it "should parse GMP::Z class" do z = YARD::Registry.at('GMP::Z') z.should_not be_nil z.docstring.should_not be_blank end it "should parse GMP::Z methods w/ bodies" do add = YARD::Registry.at('GMP::Z#+') add.docstring.should_not be_blank add.source.should_not be_nil add.source.should_not be_empty add_self = YARD::Registry.at('GMP::Z#+') add_self.docstring.should_not be_blank add_self.source.should_not be_nil add_self.source.should_not be_empty sqrtrem = YARD::Registry.at('GMP::Z#+') sqrtrem.docstring.should_not be_blank sqrtrem.source.should_not be_nil sqrtrem.source.should_not be_empty end it "should parse GMP::Z methods w/o bodies" do neg = YARD::Registry.at('GMP::Z#neg') neg.docstring.should_not be_blank neg.source.should be_nil neg_self = YARD::Registry.at('GMP::Z#neg') neg_self.docstring.should_not be_blank neg_self.source.should be_nil end end end yard-0.8.7.3/spec/parser/base_spec.rb0000644000004100000410000000151212261240652017354 0ustar www-datawww-datarequire File.join(File.dirname(__FILE__), '..', 'spec_helper') describe YARD::Parser::Base do describe '#initialize' do class MyParser < Parser::Base; def initialize(a, b) end end it "should take 2 arguments" do lambda { YARD::Parser::Base.new }.should raise_error(ArgumentError, /wrong (number|#) of arguments|given 0, expected 2/) end it "should raise NotImplementedError on #initialize" do lambda { YARD::Parser::Base.new('a', 'b') }.should raise_error(NotImplementedError) end it "should raise NotImplementedError on #parse" do lambda { MyParser.new('a', 'b').parse }.should raise_error(NotImplementedError) end it "should raise NotImplementedError on #tokenize" do lambda { MyParser.new('a', 'b').tokenize }.should raise_error(NotImplementedError) end end end yard-0.8.7.3/spec/parser/ruby/0000755000004100000410000000000012261240652016065 5ustar www-datawww-datayard-0.8.7.3/spec/parser/ruby/ruby_parser_spec.rb0000644000004100000410000002107312261240652021764 0ustar www-datawww-datarequire File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') describe YARD::Parser::Ruby::RubyParser do def stmt(stmt) YARD::Parser::Ruby::RubyParser.new(stmt, nil).parse.root.first end def stmts(stmts) YARD::Parser::Ruby::RubyParser.new(stmts, nil).parse.root end def tokenize(stmt) YARD::Parser::Ruby::RubyParser.new(stmt, nil).parse.tokens end describe '#parse' do it "should get comment line numbers" do s = stmt <<-eof # comment # comment # comment def method; end eof s.comments.should == "comment\ncomment\ncomment" s.comments_range.should == (1..3) s = stmt <<-eof # comment # comment def method; end eof s.comments.should == "comment\ncomment" s.comments_range.should == (2..3) s = stmt <<-eof # comment # comment def method; end eof s.comments.should == "comment\ncomment" s.comments_range.should == (1..2) s = stmt <<-eof # comment def method; end eof s.comments.should == "comment" s.comments_range.should == (1..1) s = stmt <<-eof def method; end # comment eof s.comments.should == "comment" s.comments_range.should == (1..1) end it "should only look up to two lines back for comments" do s = stmts <<-eof # comments # comments def method; end eof s[1].comments.should == "comments" s = stmts <<-eof # comments def method; end eof s[1].comments.should == nil ss = stmts <<-eof # comments def method; end # hello def method2; end eof ss[1].comments.should == nil ss[2].comments.should == 'hello' end it "should handle block comment followed by line comment" do ss = stmts <<-eof # comments1 =begin comments2 =end # comments3 def hello; end eof ss.last.comments.should == "comments3" end it "should handle block comment followed by block comment" do ss = stmts <<-eof =begin comments1 =end =begin comments2 =end def hello; end eof ss.last.comments.strip.should == "comments2" end it "should handle 1.9 lambda syntax with args" do src = "->(a,b,c=1,*args,&block) { hello_world }" stmt(src).source.should == src end it "should handle 1.9 lambda syntax" do src = "-> { hello_world }" stmt(src).source.should == src end it "should handle standard lambda syntax" do src = "lambda { hello_world }" stmt(src).source.should == src end it "should throw a ParserSyntaxError on invalid code" do lambda { stmt("Foo, bar.") }.should raise_error(YARD::Parser::ParserSyntaxError) end it "should handle bare hashes as method parameters" do src = "command :a => 1, :b => 2, :c => 3" stmt(src).jump(:command)[1].source.should == ":a => 1, :b => 2, :c => 3" src = "command a: 1, b: 2, c: 3" stmt(src).jump(:command)[1].source.should == "a: 1, b: 2, c: 3" end it "should handle source for hash syntax" do src = "{ :a => 1, :b => 2, :c => 3 }" stmt(src).jump(:hash).source.should == "{ :a => 1, :b => 2, :c => 3 }" end it "should handle an empty hash" do stmt("{}").jump(:hash).source.should == "{}" end it "new hash label syntax should show label without colon" do ast = stmt("{ a: 1 }").jump(:label) ast[0].should == "a" ast.source.should == "a:" end it "should handle begin/rescue blocks" do ast = stmt("begin; X; rescue => e; Y end").jump(:rescue) ast.source.should == "rescue => e; Y end" ast = stmt("begin; X; rescue A => e; Y end").jump(:rescue) ast.source.should == "rescue A => e; Y end" ast = stmt("begin; X; rescue A, B => e; Y end").jump(:rescue) ast.source.should == "rescue A, B => e; Y end" end it "should handle method rescue blocks" do ast = stmt("def x; A; rescue Y; B end") ast.source.should == "def x; A; rescue Y; B end" ast.jump(:rescue).source.should == "rescue Y; B end" end it "should handle defs with keywords as method name" do ast = stmt("# docstring\nclass A;\ndef class; end\nend") ast.jump(:class).docstring.should == "docstring" ast.jump(:class).line_range.should == (2..4) end it "should end source properly on array reference" do ast = stmt("AS[0, 1 ] ") ast.source.should == 'AS[0, 1 ]' ast = stmt("def x(a = S[1]) end").jump(:default_arg) ast.source.should == 'a = S[1]' end it "should end source properly on if/unless mod" do %w(if unless while).each do |mod| stmt("A=1 #{mod} true").source.should == "A=1 #{mod} true" end end it "should show proper source for assignment" do stmt("A=1").jump(:assign).source.should == "A=1" end it "should show proper source for a top_const_ref" do s = stmt("::\nFoo::Bar") s.jump(:top_const_ref).source.should == "::\nFoo" s.should be_ref s.jump(:top_const_ref).should be_ref s.source.should == "::\nFoo::Bar" s.line_range.to_a.should == [1, 2] end it "should show proper source for inline heredoc" do src = "def foo\n foo(<<-XML, 1, 2)\n bar\n\n XML\nend" s = stmt(src) t = tokenize(src) s.source.should == src t.map {|x| x[1] }.join.should == src end it "should show proper source for regular heredoc" do src = "def foo\n x = <<-XML\n Hello \#{name}!\n Bye!\n XML\nend" s = stmt(src) t = tokenize(src) s.source.should == src t.map {|x| x[1] }.join.should == src end it "should show proper source for heredoc with comment" do src = "def foo\n x = <<-XML # HI!\n Hello \#{name}!\n Bye!\n XML\nend" s = stmt(src) t = tokenize(src) s.source.should == src t.map {|x| x[1] }.join.should == src end it "should show proper source for string" do ["'", '"'].each do |q| src = "#{q}hello\n\nworld#{q}" s = stmt(src) s.jump(:string_content).source.should == "hello\n\nworld" s.source.should == src end src = '("this is a string")' stmt(src).jump(:string_literal).source.should == '"this is a string"' end it "should show proper source for %w() array" do src = "%w(\na b c\n d e f\n)" stmt(src).jump(:qwords_literal).source.should == src end it "should show proper source for %w{} array" do src = "%w{\na b c\n d e f\n}" stmt(src).jump(:array).source.should == src end it "should parse %w() array in constant declaration" do s = stmt(<<-eof) class Foo FOO = %w( foo bar ) end eof s.jump(:qwords_literal).source.should == '%w( foo bar )' if RUBY_VERSION >= '1.9.3' # ripper fix: array node encapsulates qwords s.jump(:array).source.should == '%w( foo bar )' end end it "should parse %w() array source in object[] parsed context" do s = stmts(<<-eof) {}[:key] FOO = %w( foo bar ) eof s[1].jump(:array).source.should == '%w( foo bar )' end it "should parse %w() array source in object[]= parsed context" do s = stmts(<<-eof) {}[:key] = :value FOO = %w( foo bar ) eof s[1].jump(:array).source.should == '%w( foo bar )' end it "should parse [] as array" do s = stmt(<<-eof) class Foo FOO = ['foo', 'bar'] end eof s.jump(:array).source.should == "['foo', 'bar']" end it "should show source for unary minus" do stmt("X = - 1").jump(:unary).source.should == '- 1' end it "should show source for unary exclamation" do stmt("X = !1").jump(:unary).source.should == '!1' end it "should have the correct line range for class/modules" do s = stmt(<<-eof) class Foo def foo; end # Ending comment end eof s.jump(:class).line_range.should == (1..7) end it "should find lone comments" do Registry.clear ast = YARD.parse_string(<<-eof).enumerator class Foo ## # comment here def foo; end # end comment end eof comment = ast.first.last.first comment.type.should == :comment comment.docstring_hash_flag.should be_true comment.docstring.strip.should == "comment here" ast.first.last.last.type.should == :comment ast.first.last.last.docstring.should == "end comment" end end end if HAVE_RIPPER yard-0.8.7.3/spec/parser/ruby/legacy/0000755000004100000410000000000012261240652017331 5ustar www-datawww-datayard-0.8.7.3/spec/parser/ruby/legacy/token_list_spec.rb0000644000004100000410000000462112261240652023046 0ustar www-datawww-datarequire File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') include YARD::Parser::Ruby::Legacy include YARD::Parser::Ruby::Legacy::RubyToken describe YARD::Parser::Ruby::Legacy::TokenList do describe "#initialize / #push" do it "should accept a tokenlist (via constructor or push)" do lambda { TokenList.new(TokenList.new) }.should_not raise_error(ArgumentError) TokenList.new.push(TokenList.new("x = 2")).size.should == 6 end it "accept a token (via constructor or push)" do lambda { TokenList.new(Token.new(0, 0)) }.should_not raise_error(ArgumentError) TokenList.new.push(Token.new(0, 0), Token.new(1, 1)).size.should == 2 end it "should accept a string and parse it as code (via constructor or push)" do lambda { TokenList.new("x = 2") }.should_not raise_error(ArgumentError) x = TokenList.new x.push("x", "=", "2") x.size.should == 6 x.to_s.should == "x\n=\n2\n" end it "should not accept any other input" do lambda { TokenList.new(:notcode) }.should raise_error(ArgumentError) end it "should not interpolate string data" do x = TokenList.new('x = "hello #{world}"') x.size.should == 6 x[4].class.should == TkDSTRING x.to_s.should == 'x = "hello #{world}"' + "\n" end it 'handles label syntax' do x = TokenList.new('a:1,b:2') x[0].class.should == TkLABEL x[0].text.should == 'a:' x[3].class.should == TkLABEL x[3].text.should == 'b:' end end describe '#to_s' do before do @t = TokenList.new @t << TkDEF.new(1, 1, "def") @t << TkSPACE.new(1, 1) @t << TkIDENTIFIER.new(1, 1, "x") @t << TkStatementEnd.new(1, 1) @t << TkSEMICOLON.new(1, 1) << TkSPACE.new(1, 1) @t << TkBlockContents.new(1, 1) @t << TkSPACE.new(1, 1) << TkEND.new(1, 1, "end") @t[0].set_text "def" @t[1].set_text " " @t[2].set_text "x" @t[4].set_text ";" @t[5].set_text " " @t[7].set_text " " @t[8].set_text "end" end it "should only show the statement portion of the tokens by default" do @t.to_s.should == "def x" end it "should show ... for the block token if all of the tokens are shown" do @t.to_s(true).should == "def x; ... end" end it "should ignore ... if show_block = false" do @t.to_s(true, false).should == "def x; end" end end endyard-0.8.7.3/spec/parser/ruby/legacy/statement_list_spec.rb0000644000004100000410000001721412261240652023734 0ustar www-datawww-datarequire File.join(File.dirname(__FILE__), '..', '..', '..', 'spec_helper') describe YARD::Parser::Ruby::Legacy::StatementList do def stmts(code) YARD::Parser::Ruby::Legacy::StatementList.new(code) end def stmt(code) stmts(code).first end it "should parse dangling block expressions" do s = stmt <<-eof if foo puts 'hi' end eof s.tokens.to_s(true).should == "if\n foo\n ...\n end" s.tokens.to_s.should == "if\n foo" s.block.to_s.should == "puts 'hi'" s = stmt <<-eof if foo || bar puts 'hi' end eof s.tokens.to_s(true).should == "if foo ||\n bar\n ...\n end" s.tokens.to_s.should == "if foo ||\n bar" s.block.to_s.should == "puts 'hi'" end it "should allow semicolons within parentheses" do s = stmt "(foo; bar)" s.tokens.to_s(true).should == "(foo; bar)" s.block.should be_nil end it "should allow for non-block statements" do s = stmt "hello_world(1, 2, 3)" s.tokens.to_s.should == "hello_world(1, 2, 3)" s.block.should be_nil end it "should allow block statements to be used as part of other block statements" do s = stmt "while (foo; bar); foo = 12; end; while" s.tokens.to_s(true).should == "while (foo; bar); ... end" s.tokens.to_s.should == "while (foo; bar)" s.block.to_s.should == "foo = 12" end it "should allow continued processing after a block" do s = stmt "if foo; end.stuff" s.tokens.to_s(true).should == "if foo; end.stuff" s.block.to_s.should == "" s = stmt "if foo; end[stuff]" s.tokens.to_s(true).should == "if foo; end[stuff]" s.block.to_s.should == "" s = stmt "if foo; hi end.map do; 123; end" s.tokens.to_s(true).should == "if foo; ... end.map do; 123; end" s.block.to_s.should == "hi" end it "should parse default arguments" do s = stmt "def foo(bar, baz = 1, bang = 2); bar; end" s.tokens.to_s(true).should == "def foo(bar, baz = 1, bang = 2) ... end" s.block.to_s.should == "bar" s = stmt "def foo bar, baz = 1, bang = 2; bar; end" s.tokens.to_s(true).should == "def foo bar, baz = 1, bang = 2; ... end" s.block.to_s.should == "bar" s = stmt "def foo bar , baz = 1 , bang = 2; bar; end" s.tokens.to_s(true).should == "def foo bar , baz = 1 , bang = 2; ... end" s.block.to_s.should == "bar" end it "should parse complex default arguments" do s = stmt "def foo(bar, baz = File.new(1, 2), bang = 3); bar; end" s.tokens.to_s(true).should == "def foo(bar, baz = File.new(1, 2), bang = 3) ... end" s.block.to_s.should == "bar" s = stmt "def foo bar, baz = File.new(1, 2), bang = 3; bar; end" s.tokens.to_s(true).should == "def foo bar, baz = File.new(1, 2), bang = 3; ... end" s.block.to_s.should == "bar" s = stmt "def foo bar , baz = File.new(1, 2) , bang = 3; bar; end" s.tokens.to_s(true).should == "def foo bar , baz = File.new(1, 2) , bang = 3; ... end" s.block.to_s.should == "bar" end it "should parse blocks with do/end" do s = stmt <<-eof foo do puts 'hi' end eof s.tokens.to_s(true).should == "foo do\n ...\n end" s.block.to_s.should == "puts 'hi'" end it "should parse blocks with {}" do s = stmt "x { y }" s.tokens.to_s(true).should == "x { ... }" s.block.to_s.should == "y" s = stmt "x() { y }" s.tokens.to_s(true).should == "x() { ... }" s.block.to_s.should == "y" end it "should parse blocks with begin/end" do s = stmt "begin xyz end" s.tokens.to_s(true).should == "begin ... end" s.block.to_s.should == "xyz" end it "should parse nested blocks" do s = stmt "foo(:x) { baz(:y) { skippy } }" s.tokens.to_s(true).should == "foo(:x) { ... }" s.block.to_s.should == "baz(:y) { skippy }" end it "should not parse hashes as blocks" do s = stmt "x({})" s.tokens.to_s(true).should == "x({})" s.block.to_s.should == "" s = stmt "x = {}" s.tokens.to_s(true).should == "x = {}" s.block.to_s.should == "" s = stmt "x(y, {})" s.tokens.to_s(true).should == "x(y, {})" s.block.to_s.should == "" end it "should parse hashes in blocks with {}" do s = stmt "x {x = {}}" s.tokens.to_s(true).should == "x {...}" s.block.to_s.should == "x = {}" end it "should parse blocks with {} in hashes" do s = stmt "[:foo, x {}]" s.tokens.to_s(true).should == "[:foo, x {}]" s.block.to_s.should == "" end it "should handle multiple methods" do s = stmt <<-eof def %; end def b; end eof s.to_s.should == "def %; end" end it "should handle nested methods" do s = stmt <<-eof def *(o) def +@; end def ~@ end end eof s.tokens.to_s(true).should == "def *(o) ... end" s.block.to_s.should == "def +@; end\n def ~@\n end" s = stmts(<<-eof) def /(other) 'hi' end def method1 def dynamic; end end eof s[1].to_s.should == "def method1\n def dynamic; end\n end" end it "should get comment line numbers" do s = stmt <<-eof # comment # comment # comment def method; end eof s.comments.should == ["comment", "comment", "comment"] s.comments_range.should == (1..3) s = stmt <<-eof # comment # comment def method; end eof s.comments.should == ["comment", "comment"] s.comments_range.should == (2..3) s = stmt <<-eof # comment # comment def method; end eof s.comments.should == ["comment", "comment"] s.comments_range.should == (1..2) s = stmt <<-eof # comment def method; end eof s.comments.should == ["comment"] s.comments_range.should == (1..1) s = stmt <<-eof def method; end # comment eof s.comments.should == ["comment"] s.comments_range.should == (1..1) end it "should only look up to two lines back for comments" do s = stmt <<-eof # comments # comments def method; end eof s.comments.should == ["comments"] s = stmt <<-eof # comments def method; end eof s.comments.should == nil ss = stmts <<-eof # comments def method; end # hello def method2; end eof ss[0].comments.should == nil ss[1].comments.should == ['hello'] end it "should handle CRLF (Windows) newlines" do s = stmts("require 'foo'\r\n\r\n# Test Test\r\n# \r\n# Example:\r\n# example code\r\ndef test\r\nend\r\n") s[1].comments.should == ['Test Test', '', 'Example:', ' example code'] end it "should handle elsif blocks" do s = stmts(stmt("if 0\n foo\nelsif 2\n bar\nend\nbaz").block) s.size.should == 2 s[1].tokens.to_s.should == "elsif 2" s[1].block.to_s.should == "bar" end it "should handle else blocks" do s = stmts(stmt("if 0\n foo\nelse\n bar\nend\nbaz").block) s.size.should == 2 s[1].tokens.to_s.should == "else" s[1].block.to_s.should == "bar" end it "should allow aliasing keywords" do ['do x', 'x do', 'end begin', 'begin end'].each do |a| s = stmt("alias #{a}\ndef foo; end") s.tokens.to_s.should == "alias #{a}" s.block.should be_nil end s = stmt("alias do x if 2 ==\n 2") s.tokens.to_s.should == "alias do x if 2 ==\n 2" end it "should not open a block on an aliased keyword block opener" do s = stmts(<<-eof) class A; alias x do end class B; end eof s[0].block.to_s.should == 'alias x do' s.size.should > 1 end it "should convert heredoc to string" do src = "<<-XML\n foo\n\nXML" s = stmt(src) s.source.should == '"foo\n\n"' end end yard-0.8.7.3/spec/parser/ruby/ast_node_spec.rb0000644000004100000410000000214512261240652021222 0ustar www-datawww-datarequire File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') require 'pp' require 'stringio' include YARD::Parser::Ruby describe YARD::Parser::Ruby::AstNode do describe "#jump" do it "should jump to the first specific inner node if found" do ast = s(:paren, s(:paren, s(:params, s(s(:ident, "hi"), s(:ident, "bye"))))) ast.jump(:params)[0][0].type.should equal(:ident) end it "should return the original ast if no inner node is found" do ast = s(:paren, s(:list, s(:list, s(s(:ident, "hi"), s(:ident, "bye"))))) ast.jump(:params).object_id.should == ast.object_id end end describe '#pretty_print' do it "should show a list of nodes" do obj = YARD::Parser::Ruby::RubyParser.parse("# x\nbye", "x").ast out = StringIO.new PP.pp(obj, out) vcall = RUBY_VERSION >= '1.9.3' ? 'vcall' : 'var_ref' out.string.should == "s(s(:#{vcall},\n" + " s(:ident, \"bye\", line: 2..2, source: 4..6),\n" + " docstring: \"x\",\n" + " line: 2..2,\n" + " source: 4..6))\n" end end end if HAVE_RIPPER yard-0.8.7.3/spec/i18n/0000755000004100000410000000000012261240652014367 5ustar www-datawww-datayard-0.8.7.3/spec/i18n/pot_generator_spec.rb0000644000004100000410000001641612261240652020606 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::I18n::PotGenerator do def create_messages(messages) yard_messages = YARD::I18n::Messages.new add_messages(yard_messages, messages) yard_messages end def add_messages(yard_messages, messages) messages.each do |id, properties| yard_message = yard_messages.register(id) (properties[:locations] || []).each do |path, line| yard_message.add_location(path, line) end (properties[:comments] || []).each do |comment| yard_message.add_comment(comment) end end end before do @generator = YARD::I18n::PotGenerator.new("..") end describe "Generate" do it "should generate the default header" do @generator.generate.should == <<-'eoh' # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2011-11-20 22:17+0900\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" eoh end it "should generate messages in location order" do @generator.stub!(:header).and_return("HEADER\n\n") messages = { "tag|see|Parser::SourceParser.parse" => { :locations => [["yard.rb", 14]], :comments => ["@see"], }, "Parses a path or set of paths" => { :locations => [["yard.rb", 12], ["yard/parser/source_parser.rb", 83]], :comments => ["YARD.parse", "YARD::Parser::SourceParser.parse"], } } add_messages(@generator.messages, messages) @generator.generate.should == <<-'eoh' HEADER # YARD.parse # YARD::Parser::SourceParser.parse #: ../yard.rb:12 #: ../yard/parser/source_parser.rb:83 msgid "Parses a path or set of paths" msgstr "" # @see #: ../yard.rb:14 msgid "tag|see|Parser::SourceParser.parse" msgstr "" eoh end end describe "Escape" do def generate_message_pot(message_id) pot = "" message = YARD::I18n::Message.new(message_id) @generator.send(:generate_message, pot, message) pot end it "should escape <\\>" do generate_message_pot("hello \\ world").should == <<-'eop' msgid "hello \\ world" msgstr "" eop end it "should escape <\">" do generate_message_pot("hello \" world").should == <<-'eop' msgid "hello \" world" msgstr "" eop end it "should escape <\\n>" do generate_message_pot("hello \n world").should == <<-'eop' msgid "hello \n" " world" msgstr "" eop end end describe "Object" do before do Registry.clear @yard = YARD::CodeObjects::ModuleObject.new(:root, :YARD) end it "should extract docstring" do object = YARD::CodeObjects::MethodObject.new(@yard, :parse, :module) do |o| o.docstring = "An alias to {Parser::SourceParser}'s parsing method" end @generator.parse_objects([object]) @generator.messages.should == create_messages({ "An alias to {Parser::SourceParser}'s parsing method" => { :locations => [], :comments => ["YARD.parse"], } }) end it "should extract location" do object = YARD::CodeObjects::MethodObject.new(@yard, :parse, :module) do |o| o.docstring = "An alias to {Parser::SourceParser}'s parsing method" o.files = [["yard.rb", 12]] end @generator.parse_objects([object]) @generator.messages.should == create_messages({ "An alias to {Parser::SourceParser}'s parsing method" => { :locations => [["yard.rb", 13]], :comments => ["YARD.parse"], } }) end it "should extract tag name" do object = YARD::CodeObjects::MethodObject.new(@yard, :parse, :module) do |o| o.docstring = "@see Parser::SourceParser.parse" o.files = [["yard.rb", 12]] end @generator.parse_objects([object]) @generator.messages.should == create_messages({ "tag|see|Parser::SourceParser.parse" => { :locations => [["yard.rb", 12]], :comments => ["@see"], }, }) end it "should extract tag text" do object = YARD::CodeObjects::MethodObject.new(@yard, :parse, :module) do |o| o.docstring = <<-eod @example Parse a glob of files YARD.parse('lib/**/*.rb') eod o.files = [["yard.rb", 12]] end @generator.parse_objects([object]) @generator.messages.should == create_messages({ "tag|example|Parse a glob of files" => { :locations => [["yard.rb", 12]], :comments => ["@example"], }, "YARD.parse('lib/**/*.rb')" => { :locations => [["yard.rb", 12]], :comments => ["@example Parse a glob of files"], } }) end it "should extract tag types" do object = YARD::CodeObjects::MethodObject.new(@yard, :parse, :module) do |o| o.docstring = <<-eod @param [String, Array] paths a path, glob, or list of paths to parse eod o.files = [["yard.rb", 12]] end @generator.parse_objects([object]) @generator.messages.should == create_messages({ "tag|param|paths" => { :locations => [["yard.rb", 12]], :comments => ["@param [String, Array]"], }, "a path, glob, or list of paths to\nparse" => { :locations => [["yard.rb", 12]], :comments => ["@param [String, Array] paths"], } }) end end describe "File" do it "should extract attribute" do path = "GettingStarted.md" text = <<-eor # @title Getting Started Guide # Getting Started with YARD eor File.stub!(:open).with(path).and_yield(StringIO.new(text)) File.stub!(:read).with(path).and_return(text) file = YARD::CodeObjects::ExtraFileObject.new(path) @generator.parse_files([file]) @generator.messages.should == create_messages({ "Getting Started Guide" => { :locations => [[path, 1]], :comments => ["title"], }, "# Getting Started with YARD" => { :locations => [[path, 3]], :comments => [], } }) end it "should extract paragraphs" do path = "README.md" paragraph1 = <<-eop.strip Note that class methods must not be referred to with the "::" namespace separator. Only modules, classes and constants should use "::". eop paragraph2 = <<-eop.strip You can also do lookups on any installed gems. Just make sure to build the .yardoc databases for installed gems with: eop text = <<-eot #{paragraph1} #{paragraph2} eot File.stub!(:open).with(path).and_yield(StringIO.new(text)) File.stub!(:read).with(path).and_return(text) file = YARD::CodeObjects::ExtraFileObject.new(path) @generator.parse_files([file]) @generator.messages.should == create_messages({ paragraph1 => { :locations => [[path, 1]], :comments => [], }, paragraph2 => { :locations => [[path, 4]], :comments => [], } }) end end end yard-0.8.7.3/spec/i18n/text_spec.rb0000644000004100000410000000752212261240652016720 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::I18n::Text do describe "#extract_messages" do def extract_messages(input, options={}) text = YARD::I18n::Text.new(StringIO.new(input), options) messages = [] text.extract_messages do |*message| messages << message end messages end describe "Header" do it "should extract attribute" do text = <<-eot # @title Getting Started Guide # Getting Started with YARD eot extract_messages(text, :have_header => true).should == [[:attribute, "title", "Getting Started Guide", 1], [:paragraph, "# Getting Started with YARD", 3]] end it "should ignore markup line" do text = <<-eot #!markdown # @title Getting Started Guide # Getting Started with YARD eot extract_messages(text, :have_header => true).should == [[:attribute, "title", "Getting Started Guide", 2], [:paragraph, "# Getting Started with YARD", 4]] end it "should terminate header block by markup line not at the first line" do text = <<-eot # @title Getting Started Guide #!markdown # Getting Started with YARD eot extract_messages(text, :have_header => true).should == [[:attribute, "title", "Getting Started Guide", 1], [:paragraph, "#!markdown", 2], [:paragraph, "# Getting Started with YARD", 4]] end end describe "Body" do it "should split to paragraphs" do paragraph1 = <<-eop.strip Note that class methods must not be referred to with the "::" namespace separator. Only modules, classes and constants should use "::". eop paragraph2 = <<-eop.strip You can also do lookups on any installed gems. Just make sure to build the .yardoc databases for installed gems with: eop text = <<-eot #{paragraph1} #{paragraph2} eot extract_messages(text).should == [[:paragraph, paragraph1, 1], [:paragraph, paragraph2, 4]] end end end describe "#translate" do def locale locale = YARD::I18n::Locale.new("fr") messages = locale.instance_variable_get(:@messages) messages["markdown"] = "markdown (markdown in fr)" messages["Hello"] = "Bonjour (Hello in fr)" messages["Paragraph 1."] = "Paragraphe 1." messages["Paragraph 2."] = "Paragraphe 2." locale end def translate(input, options={}) text = YARD::I18n::Text.new(StringIO.new(input), options) text.translate(locale) end describe "Header" do it "should extract attribute" do text = <<-eot # @title Hello # Getting Started with YARD Paragraph. eot translate(text, :have_header => true).should == <<-eot # @title Bonjour (Hello in fr) # Getting Started with YARD Paragraph. eot end it "should ignore markup line" do text = <<-eot #!markdown # @title Hello # Getting Started with YARD Paragraph. eot translate(text, :have_header => true).should == <<-eot #!markdown # @title Bonjour (Hello in fr) # Getting Started with YARD Paragraph. eot end end describe "Body" do it "should split to paragraphs" do paragraph1 = <<-eop.strip Paragraph 1. eop paragraph2 = <<-eop.strip Paragraph 2. eop text = <<-eot #{paragraph1} #{paragraph2} eot translate(text).should == <<-eot Paragraphe 1. Paragraphe 2. eot end it "should not modified non-translated message" do nonexistent_paragraph = <<-eop.strip Nonexsitent paragraph. eop text = <<-eot #{nonexistent_paragraph} eot translate(text).should == <<-eot #{nonexistent_paragraph} eot end it "should keep empty lines" do text = <<-eot Paragraph 1. Paragraph 2. eot translate(text).should == <<-eot Paragraphe 1. Paragraphe 2. eot end end end end yard-0.8.7.3/spec/i18n/locale_spec.rb0000644000004100000410000000367112261240652017174 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::I18n::Locale do def locale(name) YARD::I18n::Locale.new(name) end before do @locale = locale("fr") end describe "#name" do it "should return name" do locale("fr").name.should == "fr" end end describe "#load" do it "should return false for nonexistent PO" do File.should_receive(:exist?).with('foo/fr.po').and_return(false) @locale.load('foo').should == false end have_gettext_gem = true if RUBY_VERSION < "1.9" begin require "gettext/tools/poparser" rescue LoadError have_gettext_gem = false end else begin require "gettext/po_parser" rescue LoadError begin require "gettext/tools/poparser" rescue LoadError have_gettext_gem = false end end end it "should return true for existent PO", :if => have_gettext_gem do data = <<-eop msgid "" msgstr "" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "Hello" msgstr "Bonjour" eop parser = GetText::POParser.new File.should_receive(:exist?).with('foo/fr.po').and_return(true) GetText::POParser.should_receive(:new).and_return(parser) parser.should_receive(:parse_file) do |file, hash| file.should == 'foo/fr.po' parser.parse(data, hash) end @locale.load('foo').should == true @locale.translate('Hello').should == "Bonjour" end end describe "#translate" do before do messages = @locale.instance_variable_get(:@messages) messages["Hello"] = "Bonjour" end it "should return translated string for existent string" do @locale.translate("Hello") == "Bonjour" end it "should return original string for nonexistent string" do @locale.translate("nonexistent") == "nonexistent" end end end yard-0.8.7.3/spec/i18n/messages_spec.rb0000644000004100000410000000333312261240652017537 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::I18n::Messages do def message(id) YARD::I18n::Message.new(id) end def messages YARD::I18n::Messages.new end before do @messages = messages end describe "#each" do it "should enumerate Message" do @messages.register("Hello World!") @messages.register("Title") enumerated_messages = [] @messages.each do |message| enumerated_messages << message end enumerated_messages = enumerated_messages.sort_by {|m| m.id } enumerated_messages.should == [message("Hello World!"), message("Title")] end it "should not any Message for empty messages" do enumerated_messages = [] @messages.each do |message| enumerated_messages << message end enumerated_messages.should == [] end end describe "#[]" do it "should return registered message" do @messages.register("Hello World!") @messages["Hello World!"].should == message("Hello World!") end it "should return for nonexistent message ID" do @messages["Hello World!"].should == nil end end describe "#register" do it "should return registered message" do @messages.register("Hello World!").should == message("Hello World!") end it "should return existent message" do message = @messages.register("Hello World!") @messages.register("Hello World!").object_id.should == message.object_id end end describe "#==" do it "should return true for same value messages" do @messages.register("Hello World!") other_messages = messages other_messages.register("Hello World!") @messages.should == other_messages end end end yard-0.8.7.3/spec/i18n/message_spec.rb0000644000004100000410000000251612261240652017356 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::I18n::Message do def message(id) YARD::I18n::Message.new(id) end before do @message = message("Hello World!") end describe "#id" do it "should return ID" do message("Hello World!").id.should == "Hello World!" end end describe "#add_location" do it "should add some locations" do @message.add_location("hello.rb", 10) @message.add_location("message.rb", 5) @message.locations.should == Set.new([["hello.rb", 10], ["message.rb", 5]]) end end describe "#add_comment" do it "should add some comments" do @message.add_comment("YARD.title") @message.add_comment("Hello#message") @message.comments.should == Set.new(["YARD.title", "Hello#message"]) end end describe "#==" do it "should return true for same value messages" do locations = [["hello.rb", 10], ["message.rb", 5]] comments = ["YARD.title", "Hello#message"] other_message = message(@message.id) locations.each do |path, line| @message.add_location(path, line) other_message.add_location(path, line) end comments.each do |comment| @message.add_comment(comment) other_message.add_comment(comment) end @message.should == other_message end end end yard-0.8.7.3/spec/serializers/0000755000004100000410000000000012261240652016144 5ustar www-datawww-datayard-0.8.7.3/spec/serializers/data/0000755000004100000410000000000012261240652017055 5ustar www-datawww-datayard-0.8.7.3/spec/serializers/data/serialized_yardoc/0000755000004100000410000000000012261240652022551 5ustar www-datawww-datayard-0.8.7.3/spec/serializers/data/serialized_yardoc/checksums0000644000004100000410000000006112261240652024456 0ustar www-datawww-datatest.rb 80e5834ff1e98223761615c0917ff9b77b7ae057 yard-0.8.7.3/spec/serializers/data/serialized_yardoc/objects/0000755000004100000410000000000012261240652024202 5ustar www-datawww-datayard-0.8.7.3/spec/serializers/data/serialized_yardoc/objects/Foo/0000755000004100000410000000000012261240652024725 5ustar www-datawww-datayard-0.8.7.3/spec/serializers/data/serialized_yardoc/objects/Foo/baz_i.dat0000644000004100000410000000062312261240652026504 0ustar www-datawww-datao:$YARD::CodeObjects::MethodObject: @scope: instance:@visibility: public:@parameters[: @files[[I" test.rb:ETi[@ i:@current_file_has_commentsF: @name:baz:@source_type: ruby: @tags[:@docstringIC:YARD::Docstring" ; F: @objectIu:YARD::StubProxy Foo#baz; F: @summary0:@ref_tags[;[: @all0:@line_range0:@namespaceIu;Foo; F: @sourceI"def bar; end; F:@signatureI"def bar( ); Fyard-0.8.7.3/spec/serializers/data/serialized_yardoc/objects/Foo/bar_i.dat0000644000004100000410000000063712261240652026501 0ustar www-datawww-datao:$YARD::CodeObjects::MethodObject: @scope: instance:@visibility: public:@parameters[: @files[[I" test.rb:ETi:@current_file_has_commentsF: @name:bar:@source_type: ruby: @tags[:@docstringIC:YARD::Docstring" ; F: @objectIu:YARD::StubProxy Foo#bar; F: @summary0:@ref_tags[;[: @allI"; F:@line_range0:@namespaceIu;Foo; F: @sourceI"def bar; end; F:@signatureI"def bar( ); F:@explicitTyard-0.8.7.3/spec/serializers/data/serialized_yardoc/objects/root.dat0000644000004100000410000000075012261240652025661 0ustar www-datawww-datao:"YARD::CodeObjects::RootObject:@childrenIC:&YARD::CodeObjects::CodeObjectList[Iu:YARD::StubProxyFoo:EF: @ownerIu;; F:@class_mixinsIC;[; Iu;; F:@instance_mixinsIC;[; Iu;; F:@attributesIC:SymbolHash{: classIC;{:@symbolize_valueT: instanceIC;{;T;T: @aliases{: @files[:@current_file_has_commentsF: @name: root:@source_type: ruby: @tags[:@docstringIC:YARD::Docstring" ; F: @objectIu;; F: @summary0:@ref_tags[;[: @allI"; F:@namespace0yard-0.8.7.3/spec/serializers/data/serialized_yardoc/objects/Foo.dat0000644000004100000410000000126212261240652025420 0ustar www-datawww-datao:#YARD::CodeObjects::ClassObject:@childrenIC:&YARD::CodeObjects::CodeObjectList[Iu:YARD::StubProxy Foo#bar:EFIu; Foo#baz; F: @ownerIu;Foo; F:@class_mixinsIC;[; Iu;Foo; F:@instance_mixinsIC;[; Iu;Foo; F:@attributesIC:SymbolHash{: classIC;{:@symbolize_valueT: instanceIC;{;T;T: @aliases{Iu; Foo#baz; F:bar: @files[[I" test.rb; Ti:@current_file_has_commentsF: @name:Foo:@source_type: ruby: @tags[:@docstringIC:YARD::Docstring" ; F: @objectIu;Foo; F: @summary0:@ref_tags[;[: @allI"; F:@line_range0:@namespaceIu;; F:@superclasso:YARD::CodeObjects::Proxy : @imethod0:@origname0:@orignamespace0;: Object;"Iu;; F: @obj0yard-0.8.7.3/spec/serializers/data/serialized_yardoc/proxy_types0000644000004100000410000000003112261240652025073 0ustar www-datawww-data{I" Object:EF: classyard-0.8.7.3/spec/serializers/spec_helper.rb0000644000004100000410000000011312261240652020755 0ustar www-datawww-datarequire File.join(File.dirname(__FILE__), "..", "spec_helper") include YARDyard-0.8.7.3/spec/serializers/yardoc_serializer_spec.rb0000644000004100000410000000251512261240652023220 0ustar www-datawww-datarequire File.dirname(__FILE__) + "/spec_helper" instance_eval do class YARD::Serializers::YardocSerializer public :dump public :internal_dump end end describe YARD::Serializers::YardocSerializer do before do @serializer = YARD::Serializers::YardocSerializer.new('.yardoc') Registry.clear @foo = CodeObjects::ClassObject.new(:root, :Foo) @bar = CodeObjects::MethodObject.new(@foo, :bar) end describe '#dump' do it "should maintain object equality when loading a dumped object" do newfoo = @serializer.internal_dump(@foo) newfoo.should equal(@foo) newfoo.should == @foo @foo.should equal(newfoo) @foo.should == newfoo newfoo.hash.should == @foo.hash end it "should maintain hash key equality when loading a dumped object" do newfoo = @serializer.internal_dump(@foo) {@foo => 1}.should have_key(newfoo) {newfoo => 1}.should have_key(@foo) end end describe '#serialize' do it "should accept a hash of codeobjects (and write to root)" do data = {:root => Registry.root} marshaldata = Marshal.dump(data) filemock = mock(:file) filemock.should_receive(:write).with(marshaldata) File.should_receive(:open!).with('.yardoc/objects/root.dat', 'wb').and_yield(filemock) @serializer.serialize(data) end end endyard-0.8.7.3/spec/serializers/file_system_serializer_spec.rb0000644000004100000410000000765512261240652024274 0ustar www-datawww-datarequire File.join(File.dirname(__FILE__), "spec_helper") require 'stringio' describe YARD::Serializers::FileSystemSerializer do before do FileUtils.stub!(:mkdir_p) File.stub!(:open) end describe '#basepath' do it "should default the base path to the 'doc/'" do obj = Serializers::FileSystemSerializer.new obj.basepath.should == 'doc' end end describe '#extension' do it "should default the file extension to .html" do obj = Serializers::FileSystemSerializer.new obj.extension.should == "html" end end describe '#serialized_path' do it "should allow no extension to be used" do obj = Serializers::FileSystemSerializer.new :extension => nil yard = CodeObjects::ClassObject.new(nil, :FooBar) obj.serialized_path(yard).should == 'FooBar' end it "should serialize to top-level-namespace for root" do obj = Serializers::FileSystemSerializer.new :extension => nil obj.serialized_path(Registry.root).should == "top-level-namespace" end it "should return serialized_path for a String" do s = Serializers::FileSystemSerializer.new(:basepath => 'foo', :extension => 'txt') s.serialized_path('test.txt').should == 'test.txt' end it "should remove special chars from path" do m = CodeObjects::MethodObject.new(nil, 'a') s = Serializers::FileSystemSerializer.new { :/ => '_2F_i.html', :gsub! => 'gsub_21_i.html', :ask? => 'ask_3F_i.html', :=== => '_3D_3D_3D_i.html', :+ => '_2B_i.html', :- => '-_i.html', :[]= => '_5B_5D_3D_i.html', :<< => '_3C_3C_i.html', :>= => '_3E_3D_i.html', :` => '_60_i.html', :& => '_26_i.html', :* => '_2A_i.html', :| => '_7C_i.html', :/ => '_2F_i.html', :=~ => '_3D_7E_i.html' }.each do |meth, value| m.stub!(:name).and_return(meth) s.serialized_path(m).should == value end end it "should handle ExtraFileObject's" do s = Serializers::FileSystemSerializer.new e = CodeObjects::ExtraFileObject.new('filename.txt', '') s.serialized_path(e).should == 'file.filename.html' end it "should differentiate instance and class methods from serialized path" do s = Serializers::FileSystemSerializer.new m1 = CodeObjects::MethodObject.new(nil, 'meth') m2 = CodeObjects::MethodObject.new(nil, 'meth', :class) s.serialized_path(m1).should_not == s.serialized_path(m2) end it "should serialize path from overload tag" do YARD.parse_string <<-'eof' class Foo # @overload bar def bar; end end eof serializer = Serializers::FileSystemSerializer.new object = Registry.at('Foo#bar').tag(:overload) serializer.serialized_path(object).should == "Foo/bar_i.html" end end describe '#serialize' do it "should serialize to the correct path" do yard = CodeObjects::ClassObject.new(nil, :FooBar) meth = CodeObjects::MethodObject.new(yard, :baz, :class) meth2 = CodeObjects::MethodObject.new(yard, :baz) { 'foo/FooBar/baz_c.txt' => meth, 'foo/FooBar/baz_i.txt' => meth2, 'foo/FooBar.txt' => yard }.each do |path, obj| io = StringIO.new File.should_receive(:open).with(path, 'wb').and_yield(io) io.should_receive(:write).with("data") s = Serializers::FileSystemSerializer.new(:basepath => 'foo', :extension => 'txt') s.serialize(obj, "data") end end it "should guarantee the directory exists" do o1 = CodeObjects::ClassObject.new(nil, :Really) o2 = CodeObjects::ClassObject.new(o1, :Long) o3 = CodeObjects::ClassObject.new(o2, :PathName) obj = CodeObjects::MethodObject.new(o3, :foo) FileUtils.should_receive(:mkdir_p).once.with('doc/Really/Long/PathName') s = Serializers::FileSystemSerializer.new s.serialize(obj, "data") end end endyard-0.8.7.3/spec/code_objects/0000755000004100000410000000000012261240652016233 5ustar www-datawww-datayard-0.8.7.3/spec/code_objects/proxy_spec.rb0000644000004100000410000001025312261240652020754 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::CodeObjects::Proxy do before { Registry.clear } it "should return the object if it's in the Registry" do pathobj = ModuleObject.new(:root, :YARD) proxyobj = P(:root, :YARD) proxyobj.type.should == :module Proxy.should_not === proxyobj end it "should handle complex string namespaces" do ModuleObject.new(:root, :A) pathobj = ModuleObject.new(P(nil, :A), :B) P(:root, "A::B").should be_instance_of(ModuleObject) end it "should not return true to Proxy === obj if obj is a Proxy class holding a resolved object" do Proxy.should === P(:root, 'a') Proxy.should_not === P(:root) MethodObject.new(:root, 'a') Proxy.should_not === P(:root, 'a') x = Proxy.new(:root, 'a') Proxy.should_not === x end it "should return the object if it's an included Module" do yardobj = ModuleObject.new(:root, :YARD) pathobj = ClassObject.new(:root, :TestClass) pathobj.instance_mixins << yardobj P(P(nil, :TestClass), :YARD).should be_instance_of(ModuleObject) end it "should respond_to respond_to?" do obj = ClassObject.new(:root, :Object) yardobj = ModuleObject.new(:root, :YARD) P(:YARD).respond_to?(:children).should == true P(:NOTYARD).respond_to?(:children).should == false P(:YARD).respond_to?(:initialize).should == false P(:YARD).respond_to?(:initialize, true).should == true P(:NOTYARD).respond_to?(:initialize).should == false P(:NOTYARD).respond_to?(:initialize, true).should == true end it "should make itself obvious that it's a proxy" do pathobj = P(:root, :YARD) pathobj.class.should == Proxy (Proxy === pathobj).should == true end it "should pretend it's the object's type if it can resolve" do pathobj = ModuleObject.new(:root, :YARD) proxyobj = P(:root, :YARD) proxyobj.should be_instance_of(ModuleObject) end it "should handle instance method names" do obj = P(nil, '#test') obj.name.should == :test obj.path.should == "#test" obj.namespace.should == Registry.root end it "should handle instance method names under a namespace" do pathobj = ModuleObject.new(:root, :YARD) obj = P(pathobj, "A::B#test") obj.name.should == :test obj.path.should == "A::B#test" end it "should allow type to be changed" do obj = P("InvalidClass") obj.type.should == :proxy Proxy.should === obj obj.type = :class obj.type.should == :class end it "should NOT retain a type change between Proxy objects" do P("InvalidClass").type = :class P("InvalidClass").type.should == :proxy end it "should use type to ensure resolved object is of intended type" do YARD.parse_string <<-eof module Foo class Bar; end def self.Bar; end end eof proxy = Proxy.new(P('Foo'), 'Bar') proxy.type = :method proxy.path.should == 'Foo.Bar' end it "should allow type in initializer" do Proxy.new(Registry.root, 'Foo', :method).type.should == :method P(Registry.root, 'Foo', :method).type.should == :method end it "should never equal Registry.root" do P("MYPROXY").should_not == Registry.root P("X::A").should_not == Registry.root end it "should reset namespace and name when object is resolved" do obj1 = ModuleObject.new(:root, :YARD) obj2 = ModuleObject.new(:root, :NOTYARD) resolved = Proxy.new(obj2, :YARD) resolved.should == obj1 resolved.namespace.should == Registry.root resolved.name.should == :YARD end it "should ensure that the correct object was resolved" do foo = ModuleObject.new(:root, :Foo) foobar = ModuleObject.new(foo, :Bar) foobaz = ClassObject.new(foo, :Baz) # Remember, we're looking for Qux::Bar, not just 'Bar' proxy = Proxy.new(foobar, 'Foo::Qux::Bar') proxy.type.should == :proxy qux = ModuleObject.new(foo, :Qux) quxbar = ModuleObject.new(qux, :Bar) # Now it should resolve proxy.type.should == :module end it "should handle constant names in namespaces" do YARD.parse_string <<-eof module A; end; B = A module B::C; def foo; end end eof Proxy.new(:root, 'B::C').should == Registry.at('A::C') end end yard-0.8.7.3/spec/code_objects/extra_file_object_spec.rb0000644000004100000410000001175312261240652023251 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::CodeObjects::ExtraFileObject do describe '#initialize' do it "should attempt to read contents from filesystem if contents=nil" do File.should_receive(:read).with('file.txt').and_return('') ExtraFileObject.new('file.txt') end it "should raise Errno::ENOENT if contents=nil and file does not exist" do lambda { ExtraFileObject.new('file.txt') }.should raise_error(Errno::ENOENT) end it "should not attempt to read from disk if contents are provided" do ExtraFileObject.new('file.txt', 'CONTENTS') end it "should set filename to filename" do file = ExtraFileObject.new('a/b/c/file.txt', 'CONTENTS') file.filename.should == "a/b/c/file.txt" end it "should parse out attributes at top of the file" do file = ExtraFileObject.new('file.txt', "# @title X\n# @some_attribute Y\nFOO BAR") file.attributes[:title].should == "X" file.attributes[:some_attribute].should == "Y" file.contents.should == "FOO BAR" end it "should allow whitespace prior to '#' marker when parsing attributes" do file = ExtraFileObject.new('file.txt', " \t # @title X\nFOO BAR") file.attributes[:title].should == "X" file.contents.should == "FOO BAR" end it "should parse out old-style #!markup shebang format" do file = ExtraFileObject.new('file.txt', "#!foobar\nHello") file.attributes[:markup].should == "foobar" end it "should not parse old-style #!markup if any whitespace is found" do file = ExtraFileObject.new('file.txt', " #!foobar\nHello") file.attributes[:markup].should be_nil file.contents.should == " #!foobar\nHello" end it "should not parse out attributes if there are newlines prior to attributes" do file = ExtraFileObject.new('file.txt', "\n# @title\nFOO BAR") file.attributes.should be_empty file.contents.should == "\n# @title\nFOO BAR" end it "should set contents to data after attributes" do file = ExtraFileObject.new('file.txt', "# @title\nFOO BAR") file.contents.should == "FOO BAR" end it "should preserve newlines" do file = ExtraFileObject.new('file.txt', "FOO\r\nBAR\nBAZ") file.contents.should == "FOO\r\nBAR\nBAZ" end it "should not include newlines in attribute data" do file = ExtraFileObject.new('file.txt', "# @title FooBar\r\nHello world") file.attributes[:title].should == "FooBar" end it "should force encoding to @encoding attribute if present" do log.should_not_receive(:warn) data = "# @encoding sjis\nFOO" data.force_encoding('binary') file = ExtraFileObject.new('file.txt', data) ['Shift_JIS', 'Windows-31J'].should include(file.contents.encoding.to_s) end if YARD.ruby19? it "should warn if @encoding is invalid" do log.should_receive(:warn).with("Invalid encoding `INVALID' in file.txt") data = "# @encoding INVALID\nFOO" encoding = data.encoding file = ExtraFileObject.new('file.txt', data) file.contents.encoding.should == encoding end if YARD.ruby19? it "should ignore encoding in 1.8.x (or encoding-unaware platforms)" do log.should_not_receive(:warn) file = ExtraFileObject.new('file.txt', "# @encoding INVALID\nFOO") end if YARD.ruby18? it "should attempt to re-parse data as 8bit ascii if parsing fails" do log.should_not_receive(:warn) str, out = *(["\xB0"] * 2) if str.respond_to?(:force_encoding) str.force_encoding('utf-8') out.force_encoding('binary') end file = ExtraFileObject.new('file.txt', str) file.contents.should == out end end describe '#name' do it "should be set to basename (not extension) of filename" do file = ExtraFileObject.new('file.txt', '') file.name.should == 'file' end end describe '#title' do it "should return @title attribute if present" do file = ExtraFileObject.new('file.txt', '# @title FOO') file.title.should == 'FOO' end it "should return #name if no @title attribute exists" do file = ExtraFileObject.new('file.txt', '') file.title.should == 'file' end end describe '#locale=' do it "should translate contents" do file = ExtraFileObject.new('file.txt', 'Hello') file.locale = 'fr' fr_locale = I18n::Locale.new('fr') fr_messages = fr_locale.instance_variable_get(:@messages) fr_messages["Hello"] = 'Bonjour' Registry.should_receive(:locale).with('fr').and_return(fr_locale) file.contents.should == 'Bonjour' end end describe '#==' do it "should define equality on filename alone" do file1 = ExtraFileObject.new('file.txt', 'A') file2 = ExtraFileObject.new('file.txt', 'B') file1.should == file2 file1.should be_eql(file2) file1.should be_equal(file2) # Another way to test the equality interface a = [file1] a |= [file2] a.size.should == 1 end end end yard-0.8.7.3/spec/code_objects/class_object_spec.rb0000644000004100000410000001527512261240652022237 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::CodeObjects::ClassObject do describe '#inheritance_tree' do before(:all) do Registry.clear @mixin = ModuleObject.new(:root, :SomeMixin) @mixin2 = ModuleObject.new(:root, :SomeMixin2) @mixin2.instance_mixins << @mixin @mixin3 = ModuleObject.new(:root, :SomeMixin3) @mixin4 = ModuleObject.new(:root, :SomeMixin4) @mixin2.instance_mixins << @mixin3 @superyard = ClassObject.new(:root, :SuperYard) @superyard.superclass = P("String") @superyard.instance_mixins << @mixin2 @superyard.class_mixins << @mixin4 @yard = ClassObject.new(:root, :YARD) @yard.superclass = @superyard @yard.instance_mixins << @mixin end it "should show the proper inheritance tree" do @yard.inheritance_tree.should == [@yard, @superyard, P(:String)] end it "should show proper inheritance tree when mixins are included" do @yard.inheritance_tree(true).should == [@yard, @mixin, @superyard, @mixin4, @mixin2, @mixin3, P(:String)] end it "should not modify the object's mixin list when mixins are included" do @class1 = ClassObject.new(:root, :A) @class2 = ClassObject.new(:root, :B) @class2.superclass = @class1 @class2.inheritance_tree(true) @class2.mixins.should == [] end it "should list class mixins in inheritance tree" do mod = ModuleObject.new(:root, :ClassMethods) klass = ClassObject.new(:root, :ReceivingClass) klass.class_mixins << mod klass.inheritance_tree(true).should == [klass, mod] end end describe "#meths / #inherited_meths" do before(:all) do Registry.clear YARD.parse_string <<-eof class SuperYard < String def foo; end def foo2; end def bar; end def middle; end protected :foo2 private def self.bar; end end class MiddleYard < SuperYard def middle; end end class YARD < MiddleYard def mymethod; end def bar; end end module IncludedYard def foo; end end class FinalYard < SuperYard include IncludedYard end eof end it "should show inherited methods by default" do meths = P(:YARD).meths meths.should include(P("YARD#mymethod")) meths.should include(P("SuperYard#foo")) meths.should include(P("SuperYard#foo2")) meths.should include(P("SuperYard.bar")) end it "should allow :inherited to be set to false" do meths = P(:YARD).meths(:inherited => false) meths.should include(P("YARD#mymethod")) meths.should_not include(P("SuperYard#foo")) meths.should_not include(P("SuperYard#foo2")) meths.should_not include(P("SuperYard.bar")) end it "should not show overridden methods" do meths = P(:YARD).meths meths.should include(P("YARD#bar")) meths.should_not include(P("SuperYard#bar")) meths = P(:YARD).inherited_meths meths.should_not include(P("YARD#bar")) meths.should_not include(P("YARD#mymethod")) meths.should include(P("SuperYard#foo")) meths.should include(P("SuperYard#foo2")) meths.should include(P("SuperYard.bar")) end it "should not show inherited methods overridden by other subclasses" do meths = P(:YARD).inherited_meths meths.should include(P('MiddleYard#middle')) meths.should_not include(P('SuperYard#middle')) end it "should show mixed in methods before superclass method" do meths = P(:FinalYard).meths meths.should include(P('IncludedYard#foo')) meths.should_not include(P('SuperYard#foo')) end end describe "#constants / #inherited_constants" do before(:all) do Registry.clear Parser::SourceParser.parse_string <<-eof class YARD CONST1 = 1 CONST2 = "hello" CONST4 = 0 end class SUPERYARD < YARD CONST4 = 5 end class SubYard < SUPERYARD CONST2 = "hi" CONST3 = "foo" end eof end it "should list inherited constants by default" do consts = P(:SubYard).constants consts.should include(P("YARD::CONST1")) consts.should include(P("SubYard::CONST3")) consts = P(:SubYard).inherited_constants consts.should include(P("YARD::CONST1")) consts.should_not include(P("YARD::CONST2")) consts.should_not include(P("SubYard::CONST2")) consts.should_not include(P("SubYard::CONST3")) end it "should not list inherited constants if turned off" do consts = P(:SubYard).constants(:inherited => false) consts.should_not include(P("YARD::CONST1")) consts.should include(P("SubYard::CONST3")) end it "should not include an inherited constant if it is overridden by the object" do consts = P(:SubYard).constants consts.should include(P("SubYard::CONST2")) consts.should_not include(P("YARD::CONST2")) end it "should not include an inherited constant if it is overridden by another subclass" do consts = P(:SubYard).inherited_constants consts.should include(P("SUPERYARD::CONST4")) consts.should_not include(P("YARD::CONST4")) end it "should not set a superclass on BasicObject class" do o = ClassObject.new(:root, :Object) o.superclass.should == P(:BasicObject) end it "should set superclass of Object to BasicObject" do o = ClassObject.new(:root, :BasicObject) o.superclass.should be_nil end it "should raise ArgumentError if superclass == self" do lambda do o = ClassObject.new(:root, :Object) do |o| o.superclass = :Object end end.should raise_error(ArgumentError) end it "should tell the world if it is an exception class" do o = ClassObject.new(:root, :MyClass) o2 = ClassObject.new(:root, :OtherClass) o2.superclass = :SystemCallError o3 = ClassObject.new(:root, :StandardError) o3.superclass = :Object o4 = ClassObject.new(:root, :Object) o.superclass = :Object o.is_exception?.should == false o.superclass = :Exception o.is_exception?.should == true o.superclass = :NoMethodError o.is_exception?.should == true o.superclass = o2 o.is_exception?.should == true o.superclass = o3 o.is_exception?.should == true end it "should not raise ArgumentError if superclass is proxy in different namespace" do lambda do o = ClassObject.new(:root, :X) do |o| o.superclass = P('OTHER::X') end end.should_not raise_error(ArgumentError) end end endyard-0.8.7.3/spec/code_objects/spec_helper.rb0000644000004100000410000000012312261240652021045 0ustar www-datawww-datarequire File.join(File.dirname(__FILE__), "..", "spec_helper") include CodeObjectsyard-0.8.7.3/spec/code_objects/constants_spec.rb0000644000004100000410000000533712261240652021616 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::CodeObjects, "CONSTANTMATCH" do it "should match a constant" do "Constant"[CodeObjects::CONSTANTMATCH].should == "Constant" "identifier"[CodeObjects::CONSTANTMATCH].should be_nil "File.new"[CodeObjects::CONSTANTMATCH].should == "File" end end describe YARD::CodeObjects, "NAMESPACEMATCH" do it "should match a namespace (multiple constants with ::)" do "Constant"[CodeObjects::NAMESPACEMATCH].should == "Constant" "A::B::C.new"[CodeObjects::NAMESPACEMATCH].should == "A::B::C" end end describe YARD::CodeObjects, "METHODNAMEMATCH" do it "should match a method name" do "method"[CodeObjects::METHODNAMEMATCH].should == "method" "[]()"[CodeObjects::METHODNAMEMATCH].should == "[]" "-@"[CodeObjects::METHODNAMEMATCH].should == "-@" "method?"[CodeObjects::METHODNAMEMATCH].should == "method?" "method!!"[CodeObjects::METHODNAMEMATCH].should == "method!" end end describe YARD::CodeObjects, "METHODMATCH" do it "should match a full class method path" do "method"[CodeObjects::METHODMATCH].should == "method" "A::B::C.method?"[CodeObjects::METHODMATCH].should == "A::B::C.method?" "A::B::C :: method"[CodeObjects::METHODMATCH].should == "A::B::C :: method" "SomeClass . method"[CodeObjects::METHODMATCH].should == "SomeClass . method" end it "should match self.method" do "self :: method!"[CodeObjects::METHODMATCH].should == "self :: method!" "self.is_a?"[CodeObjects::METHODMATCH].should == "self.is_a?" end end describe YARD::CodeObjects, "BUILTIN_EXCEPTIONS" do it "should include all base exceptions" do YARD::CodeObjects::BUILTIN_EXCEPTIONS.each do |name| eval(name).should <= Exception end end end describe YARD::CodeObjects, "BUILTIN_CLASSES" do it "should include all base classes" do YARD::CodeObjects::BUILTIN_CLASSES.each do |name| next if name == "MatchingData" && !defined?(::MatchingData) next if name == "Continuation" eval(name).should be_instance_of(Class) end end it "should include all exceptions" do YARD::CodeObjects::BUILTIN_EXCEPTIONS.each do |name| YARD::CodeObjects::BUILTIN_CLASSES.should include(name) end end end describe YARD::CodeObjects, "BUILTIN_ALL" do it "should include classes modules and exceptions" do a = YARD::CodeObjects::BUILTIN_ALL b = YARD::CodeObjects::BUILTIN_CLASSES c = YARD::CodeObjects::BUILTIN_MODULES a.should == b+c end end describe YARD::CodeObjects, "BUILTIN_MODULES" do it "should include all base modules" do YARD::CodeObjects::BUILTIN_MODULES.each do |name| next if YARD.ruby19? && ["Precision"].include?(name) eval(name).should be_instance_of(Module) end end endyard-0.8.7.3/spec/code_objects/module_object_spec.rb0000644000004100000410000001114712261240652022411 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::CodeObjects::ModuleObject do describe "#meths" do before do Registry.clear # setup the object space: # # YARD:module # YARD#foo:method # YARD#foo2:method # YARD#xyz:method # YARD.bar:method # SomeMod#mixmethod # SomeMod#xyz:method # @yard = ModuleObject.new(:root, :YARD) MethodObject.new(@yard, :foo) MethodObject.new(@yard, :xyz) MethodObject.new(@yard, :foo2) do |o| o.visibility = :protected end MethodObject.new(@yard, :bar, :class) do |o| o.visibility = :private end @other = ModuleObject.new(:root, :SomeMod) MethodObject.new(@other, :mixmethod) MethodObject.new(@other, :xyz) MethodObject.new(@other, :baz, :class) @another = ModuleObject.new(:root, :AnotherMod) MethodObject.new(@another, :fizz) MethodObject.new(@another, :bar) MethodObject.new(@another, :fazz, :class) @yard.instance_mixins << @other @yard.class_mixins << @another end it "should list all methods (including mixin methods) via #meths" do meths = @yard.meths meths.should include(P("YARD#foo")) meths.should include(P("YARD#foo2")) meths.should include(P("YARD.bar")) meths.should include(P("SomeMod#mixmethod")) meths.should include(P("AnotherMod#fizz")) end it "should allow :visibility to be set" do meths = @yard.meths(:visibility => :public) meths.should_not include(P("YARD.bar")) meths = @yard.meths(:visibility => [:public, :private]) meths.should include(P("YARD#foo")) meths.should include(P("YARD.bar")) meths.should_not include(P("YARD#foo2")) end it "should only display class methods for :scope => :class" do meths = @yard.meths(:scope => :class) meths.should_not include(P("YARD#foo")) meths.should_not include(P("YARD#foo2")) meths.should_not include(P("SomeMod#mixmethod")) meths.should_not include(P("SomeMod.baz")) meths.should_not include(P("AnotherMod#fazz")) meths.should include(P("YARD.bar")) meths.should include(P("AnotherMod#fizz")) end it "should only display instance methods for :scope => :class" do meths = @yard.meths(:scope => :instance) meths.should include(P("YARD#foo")) meths.should include(P("YARD#foo2")) meths.should include(P("SomeMod#mixmethod")) meths.should_not include(P("YARD.bar")) meths.should_not include(P("AnotherMod#fizz")) end it "should allow :included to be set" do meths = @yard.meths(:included => false) meths.should_not include(P("SomeMod#mixmethod")) meths.should_not include(P("AnotherMod#fizz")) meths.should include(P("YARD#foo")) meths.should include(P("YARD#foo2")) meths.should include(P("YARD.bar")) end it "should choose the method defined in the class over an included module" do meths = @yard.meths meths.should_not include(P("SomeMod#xyz")) meths.should include(P("YARD#xyz")) meths.should_not include(P("AnotherMod#bar")) meths.should include(P("YARD.bar")) meths = @other.meths meths.should include(P("SomeMod#xyz")) meths = @another.meths meths.should include(P("AnotherMod#bar")) end end describe "#inheritance_tree" do before do Registry.clear @mod1 = ModuleObject.new(:root, :Mod1) @mod2 = ModuleObject.new(:root, :Mod2) @mod3 = ModuleObject.new(:root, :Mod3) @mod4 = ModuleObject.new(:root, :Mod4) @mod5 = ModuleObject.new(:root, :Mod5) @mod1.instance_mixins << @mod2 @mod2.instance_mixins << @mod3 @mod3.instance_mixins << @mod4 @mod1.instance_mixins << @mod4 @proxy = P(:SomeProxyClass) @mod5.instance_mixins << @proxy end it "should show only itself for an inheritance tree without included modules" do @mod1.inheritance_tree.should == [@mod1] end it "should show proper inheritance three when modules are included" do @mod1.inheritance_tree(true).should == [@mod1, @mod2, @mod3, @mod4] end it "should not list inheritance tree of proxy objects in inheritance tree" do @proxy.should_not_receive(:inheritance_tree) @mod5.instance_mixins.should == [@proxy] end it "should list class mixins in inheritance tree" do mod = ModuleObject.new(:root, :ClassMethods) recvmod = ModuleObject.new(:root, :ReceivingModule) recvmod.class_mixins << mod recvmod.inheritance_tree(true).should == [recvmod, mod] end end endyard-0.8.7.3/spec/code_objects/method_object_spec.rb0000644000004100000410000001336212261240652022405 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::CodeObjects::MethodObject do before do Registry.clear @yard = ModuleObject.new(:root, :YARD) end it "should have a path of testing for an instance method in the root" do meth = MethodObject.new(:root, :testing) meth.path.should == "#testing" end it "should have a path of YARD#testing for an instance method in YARD" do meth = MethodObject.new(@yard, :testing) meth.path.should == "YARD#testing" end it "should have a path of YARD.testing for a class method in YARD" do meth = MethodObject.new(@yard, :testing, :class) meth.path.should == "YARD.testing" end it "should have a path of ::testing (note the ::) for a class method added to root namespace" do meth = MethodObject.new(:root, :testing, :class) meth.path.should == "::testing" end it "should exist in the registry after successful creation" do obj = MethodObject.new(@yard, :something, :class) Registry.at("YARD.something").should_not be_nil Registry.at("YARD#something").should be_nil Registry.at("YARD::something").should be_nil obj = MethodObject.new(@yard, :somethingelse) Registry.at("YARD#somethingelse").should_not be_nil end it "should allow #scope to be changed after creation" do obj = MethodObject.new(@yard, :something, :class) Registry.at("YARD.something").should_not be_nil obj.scope = :instance Registry.at("YARD.something").should be_nil Registry.at("YARD#something").should_not be_nil end it "should create object in :class scope if scope is :module" do obj = MethodObject.new(@yard, :module_func, :module) obj.scope.should == :class obj.visibility.should == :public Registry.at('YARD.module_func').should_not be_nil end it "should create second private instance method if scope is :module" do MethodObject.new(@yard, :module_func, :module) obj = Registry.at('YARD#module_func') obj.should_not be_nil obj.visibility.should == :private obj.scope.should == :instance end it "should yield block to second method if scope is :module" do MethodObject.new(@yard, :module_func, :module) do |o| o.docstring = 'foo' end Registry.at('YARD.module_func').docstring.should == 'foo' Registry.at('YARD#module_func').docstring.should == 'foo' end describe '#name' do it "should show a prefix for an instance method when prefix=true" do obj = MethodObject.new(nil, :something) obj.name(true).should == "#something" end it "should never show a prefix for a class method" do obj = MethodObject.new(nil, :something, :class) obj.name.should == :"something" obj.name(true).should == "something" end end describe '#is_attribute?' do it "should only return true if attribute is set in namespace for read/write" do obj = MethodObject.new(@yard, :foo) @yard.attributes[:instance][:foo] = {:read => obj, :write => nil} obj.is_attribute?.should be_true MethodObject.new(@yard, :foo=).is_attribute?.should be_false end end describe '#attr_info' do it "should return attribute info if namespace is available" do obj = MethodObject.new(@yard, :foo) @yard.attributes[:instance][:foo] = {:read => obj, :write => nil} obj.attr_info.should == @yard.attributes[:instance][:foo] end it "should return nil if namespace is proxy" do obj = MethodObject.new(P(:ProxyClass), :foo) MethodObject.new(@yard, :foo).attr_info.should == nil end it "should return nil if meth is not an attribute" do MethodObject.new(@yard, :notanattribute).attr_info.should == nil end end describe '#writer?' do it "should return true if method is a writer attribute" do obj = MethodObject.new(@yard, :foo=) @yard.attributes[:instance][:foo] = {:read => nil, :write => obj} obj.writer?.should == true MethodObject.new(@yard, :NOTfoo=).writer?.should == false end end describe '#reader?' do it "should return true if method is a reader attribute" do obj = MethodObject.new(@yard, :foo) @yard.attributes[:instance][:foo] = {:read => obj, :write => nil} obj.reader?.should == true MethodObject.new(@yard, :NOTfoo).reader?.should == false end end describe '#constructor?' do before { @class = ClassObject.new(:root, :MyClass) } it "should mark the #initialize method as constructor" do MethodObject.new(@class, :initialize) end it "should not mark Klass.initialize as constructor" do MethodObject.new(@class, :initialize, :class).constructor?.should be_false end it "should not mark module method #initialize as constructor" do MethodObject.new(@yard, :initialize).constructor?.should be_false end end describe '#overridden_method' do before { Registry.clear } it "should return overridden method from mixin first" do YARD.parse_string(<<-eof) module C; def foo; end end class A; def foo; end end class B < A; include C; def foo; end end eof Registry.at('B#foo').overridden_method.should == Registry.at('C#foo') end it "should return overridden method from superclass" do YARD.parse_string(<<-eof) class A; def foo; end end class B < A; def foo; end end eof Registry.at('B#foo').overridden_method.should == Registry.at('A#foo') end it "should return nil if none is found" do YARD.parse_string(<<-eof) class A; end class B < A; def foo; end end eof Registry.at('B#foo').overridden_method.should be_nil end it "should return nil if namespace is a proxy" do YARD.parse_string "def ARGV.foo; end" Registry.at('ARGV.foo').overridden_method.should be_nil end end end yard-0.8.7.3/spec/code_objects/code_object_list_spec.rb0000644000004100000410000000152712261240652023072 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::CodeObjects::CodeObjectList do before { Registry.clear } it "pushing a value should only allow CodeObjects::Base, String or Symbol" do list = CodeObjectList.new(nil) lambda { list.push(:hash => 1) }.should raise_error(ArgumentError) list << "Test" list << :Test2 list << ModuleObject.new(nil, :YARD) list.size.should == 3 end it "added value should be a proxy if parameter was String or Symbol" do list = CodeObjectList.new(nil) list << "Test" list.first.class.should == Proxy end it "should contain a unique list of objects" do obj = ModuleObject.new(nil, :YARD) list = CodeObjectList.new(nil) list << P(:YARD) list << obj list.size.should == 1 list << :Test list << "Test" list.size.should == 2 end endyard-0.8.7.3/spec/code_objects/base_spec.rb0000644000004100000410000003500312261240652020505 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::CodeObjects::Base do before { Registry.clear } # Fix this # it "should not allow empty object name" do # lambda { Base.new(:root, '') }.should raise_error(ArgumentError) # end it "should return a unique instance of any registered object" do obj = ClassObject.new(:root, :Me) obj2 = ClassObject.new(:root, :Me) obj.object_id.should == obj2.object_id obj3 = ModuleObject.new(obj, :Too) obj4 = CodeObjects::Base.new(obj3, :Hello) obj4.parent = obj obj5 = CodeObjects::Base.new(obj3, :hello) obj4.object_id.should_not == obj5.object_id end it "should create a new object if cached object is not of the same class" do ConstantObject.new(:root, "MYMODULE").should be_instance_of(ConstantObject) ModuleObject.new(:root, "MYMODULE").should be_instance_of(ModuleObject) ClassObject.new(:root, "MYMODULE").should be_instance_of(ClassObject) YARD::Registry.at("MYMODULE").should be_instance_of(ClassObject) end it "should simplify complex namespace paths" do obj = ClassObject.new(:root, "A::B::C::D") obj.name.should == :D obj.path.should == "A::B::C::D" obj.namespace.should == P("A::B::C") end # @bug gh-552 it "should simplify complex namespace paths when path starts with ::" do obj = ClassObject.new(:root, "::A::B::C::D") obj.name.should == :D obj.path.should == "A::B::C::D" obj.namespace.should == P("A::B::C") end it "should recall the block if #new is called on an existing object" do o1 = ClassObject.new(:root, :Me) do |o| o.docstring = "DOCSTRING" end o2 = ClassObject.new(:root, :Me) do |o| o.docstring = "NOT_DOCSTRING" end o1.object_id.should == o2.object_id o1.docstring.should == "NOT_DOCSTRING" o2.docstring.should == "NOT_DOCSTRING" end it "should allow complex name and convert that to namespace" do obj = CodeObjects::Base.new(nil, "A::B") obj.namespace.path.should == "A" obj.name.should == :B end it "should allow namespace to be nil and not register in the Registry" do obj = CodeObjects::Base.new(nil, :Me) obj.namespace.should == nil Registry.at(:Me).should == nil end it "should allow namespace to be a NamespaceObject" do ns = ModuleObject.new(:root, :Name) obj = CodeObjects::Base.new(ns, :Me) obj.namespace.should == ns end it "should allow :root to be the shorthand namespace of `Registry.root`" do obj = CodeObjects::Base.new(:root, :Me) obj.namespace.should == Registry.root end it "should not allow any other types as namespace" do lambda { CodeObjects::Base.new("ROOT!", :Me) }.should raise_error(ArgumentError) end it "should register itself in the registry if namespace is supplied" do obj = ModuleObject.new(:root, :Me) Registry.at(:Me).should == obj obj2 = ModuleObject.new(obj, :Too) Registry.at(:"Me::Too").should == obj2 end it "should set any attribute using #[]=" do obj = ModuleObject.new(:root, :YARD) obj[:some_attr] = "hello" obj[:some_attr].should == "hello" end it "#[]= should use the accessor method if available" do obj = CodeObjects::Base.new(:root, :YARD) obj[:source] = "hello" obj.source.should == "hello" obj.source = "unhello" obj[:source].should == "unhello" end it "should set attributes via attr= through method_missing" do obj = CodeObjects::Base.new(:root, :YARD) obj.something = 2 obj.something.should == 2 obj[:something].should == 2 end it "should exist in the parent's #children after creation" do obj = ModuleObject.new(:root, :YARD) obj2 = MethodObject.new(obj, :testing) obj.children.should include(obj2) end it "should properly re-indent source starting from 0 indentation" do obj = CodeObjects::Base.new(nil, :test) obj.source = <<-eof def mymethod if x == 2 && 5 == 5 3 else 1 end end eof obj.source.should == "def mymethod\n if x == 2 &&\n 5 == 5\n 3\n else\n 1\n end\nend" Registry.clear Parser::SourceParser.parse_string <<-eof def key?(key) super(key) end eof Registry.at('#key?').source.should == "def key?(key)\n super(key)\nend" Registry.clear Parser::SourceParser.parse_string <<-eof def key?(key) if x == 2 puts key else exit end end eof Registry.at('#key?').source.should == "def key?(key)\n if x == 2\n puts key\n else\n exit\n end\nend" end it "should not add newlines to source when parsing sub blocks" do Parser::SourceParser.parse_string <<-eof module XYZ module ZYX class ABC def msg hello_world end end end end eof Registry.at('XYZ::ZYX::ABC#msg').source.should == "def msg\n hello_world\nend" end it "should handle source for 'def x; end'" do Registry.clear Parser::SourceParser.parse_string "def x; 2 end" Registry.at('#x').source.should == "def x; 2 end" end it "should set file and line information" do Parser::SourceParser.parse_string <<-eof class X; end eof Registry.at(:X).file.should == '(stdin)' Registry.at(:X).line.should == 1 end it "should maintain all file associations when objects are defined multiple times in one file" do Parser::SourceParser.parse_string <<-eof class X; end class X; end class X; end eof Registry.at(:X).file.should == '(stdin)' Registry.at(:X).line.should == 1 Registry.at(:X).files.should == [['(stdin)', 1], ['(stdin)', 2], ['(stdin)', 3]] end it "should maintain all file associations when objects are defined multiple times in multiple files" do 3.times do |i| File.stub!(:read_binary).and_return("class X; end") Parser::SourceParser.new.parse("file#{i+1}.rb") end Registry.at(:X).file.should == 'file1.rb' Registry.at(:X).line.should == 1 Registry.at(:X).files.should == [['file1.rb', 1], ['file2.rb', 1], ['file3.rb', 1]] end it "should prioritize the definition with a docstring when returning #file" do Parser::SourceParser.parse_string <<-eof class X; end class X; end # docstring class X; end eof Registry.at(:X).file.should == '(stdin)' Registry.at(:X).line.should == 4 Registry.at(:X).files.should == [['(stdin)', 4], ['(stdin)', 1], ['(stdin)', 2]] end describe '#format' do it "should send to Templates.render" do object = MethodObject.new(:root, :method) Templates::Engine.should_receive(:render).with(:x => 1, :object => object) object.format :x => 1 end end describe '#source_type' do it "should default source_type to :ruby" do object = MethodObject.new(:root, :method) object.source_type.should == :ruby end end describe '#relative_path' do it "should accept a string" do YARD.parse_string "module A; class B; end; class C; end; end" Registry.at('A::B').relative_path(Registry.at('A::C')).should == Registry.at('A::B').relative_path('A::C') end it "should return full class name when objects share a common class prefix" do YARD.parse_string "module User; end; module UserManager; end" Registry.at('User').relative_path('UserManager').should == 'UserManager' Registry.at('User').relative_path(Registry.at('UserManager')).should == 'UserManager' end it "should return the relative path when they share a common namespace" do YARD.parse_string "module A; class B; end; class C; end; end" Registry.at('A::B').relative_path(Registry.at('A::C')).should == 'C' YARD.parse_string "module Foo; module A; end; module B; def foo; end end end" Registry.at('Foo::A').relative_path(Registry.at('Foo::B#foo')).should == 'B#foo' end it "should return the full path if they don't have a common namespace" do YARD.parse_string "module A; class B; end; end; module D; class C; end; end" Registry.at('A::B').relative_path('D::C').should == 'D::C' YARD.parse_string 'module C::B::C; module Apple; end; module Ant; end end' Registry.at('C::B::C::Apple').relative_path('C::B::C::Ant').should == 'Ant' YARD.parse_string 'module OMG::ABC; end; class Object; end' Registry.at('OMG::ABC').relative_path('Object').should == "Object" YARD.parse_string("class YARD::Config; MYCONST = 1; end") Registry.at('YARD::Config').relative_path('YARD::Config::MYCONST').should == "MYCONST" end it "should return a relative path for class methods" do YARD.parse_string "module A; def self.b; end; def self.c; end; end" Registry.at('A.b').relative_path('A.c').should == 'c' Registry.at('A').relative_path('A.c').should == 'c' end it "should return a relative path for instance methods" do YARD.parse_string "module A; def b; end; def c; end; end" Registry.at('A#b').relative_path('A#c').should == '#c' Registry.at('A').relative_path('A#c').should == '#c' end it "should return full path if relative path is to parent namespace" do YARD.parse_string "module A; module B; end end" Registry.at('A::B').relative_path('A').should == 'A' end it "should only return name for relative path to self" do YARD.parse_string("class A::B::C; def foo; end end") Registry.at('A::B::C').relative_path('A::B::C').should == 'C' Registry.at('A::B::C#foo').relative_path('A::B::C#foo').should == '#foo' end end describe '#docstring=' do it "should convert string into Docstring when #docstring= is set" do o = ClassObject.new(:root, :Me) o.docstring = "DOCSTRING" o.docstring.should be_instance_of(Docstring) end it "should set docstring to docstring of other object if docstring is '(see Path)'" do ClassObject.new(:root, :AnotherObject) {|x| x.docstring = "FOO" } o = ClassObject.new(:root, :Me) o.docstring = '(see AnotherObject)' o.docstring.should == "FOO" end it "should not copy docstring mid-docstring" do doc = "Hello.\n(see file.rb)\nmore documentation" o = ClassObject.new(:root, :Me) o.docstring = doc o.docstring.should == doc end it "should allow extra docstring after (see Path)" do ClassObject.new(:root, :AnotherObject) {|x| x.docstring = "FOO" } o = ClassObject.new(:root, :Me) o.docstring = Docstring.new("(see AnotherObject)\n\nEXTRA\n@api private", o) o.docstring.should == "FOO\n\nEXTRA" o.docstring.should have_tag(:api) end end describe '#docstring' do it "should return empty string if docstring was '(see Path)' and Path is not resolved" do o = ClassObject.new(:root, :Me) o.docstring = '(see AnotherObject)' o.docstring.should == "" end it "should return docstring when object is resolved" do o = ClassObject.new(:root, :Me) o.docstring = '(see AnotherObject)' o.docstring.should == "" ClassObject.new(:root, :AnotherObject) {|x| x.docstring = "FOO" } o.docstring.should == "FOO" end describe 'localization' do it "should return localized docstring" do fr_locale = YARD::I18n::Locale.new('fr') fr_locale.stub!(:translate).with('Hello').and_return('Bonjour') o = ClassObject.new(:root, :Me) o.docstring = 'Hello' o.docstring.should == 'Hello' Registry.stub!(:locale).with('fr').and_return(fr_locale) o.docstring('fr').should == "Bonjour" end it "should return updated localized docstring" do fr_locale = YARD::I18n::Locale.new('fr') Registry.stub!(:locale).with('fr').and_return(fr_locale) o = ClassObject.new(:root, :Me) o.docstring = 'Hello' o.docstring.should == 'Hello' fr_locale.stub!(:translate).with('Hello').and_return('Bonjour') o.docstring('fr').should == "Bonjour" o.docstring = 'World' fr_locale.stub!(:translate).with('World').and_return('Monde') o.docstring('fr').should == "Monde" o.docstring.should == 'World' end end end describe '#add_file' do it "should only add a file/line combination once" do o = ClassObject.new(:root, :Me) o.add_file('filename', 12) o.files.should == [['filename', 12]] o.add_file('filename', 12) o.files.should == [['filename', 12]] o.add_file('filename', 40) # different line o.files.should == [['filename', 12], ['filename', 40]] end end describe '#copy_to' do it "should copy all data to new object" do YARD.parse_string <<-eof private # A docstring # @return [String] a tag def foo(a, b, c) source_code_here end eof foo_c = MethodObject.new(:root, :foo, :class) Registry.at('#foo').copy_to(foo_c) foo_c.scope.should == :class foo_c.visibility.should == :private foo_c.type.should == :method foo_c.class.should == MethodObject foo_c.path.should == '::foo' foo_c.docstring.should == "A docstring" foo_c.tag(:return).types.should == ['String'] foo_c.file.should == '(stdin)' foo_c.line.should == 4 foo_c.source.should =~ /source_code_here/ foo_c.signature.should == 'def foo(a, b, c)' foo_c.parameters.should == [['a', nil], ['b', nil], ['c', nil]] end it "should return copied object" do YARD.parse_string 'def foo; end' foo_c = MethodObject.new(:root, :foo, :class) Registry.at('#foo').copy_to(foo_c).should == foo_c end it "should copy docstring and rewrite tags for new object" do YARD.parse_string <<-eof # @return [String] a tag def foo; end eof foo_c = MethodObject.new(:root, :foo, :class) foo_i = Registry.at('#foo') foo_i.copy_to(foo_c) foo_i.tags.should_not == foo_c.tags foo_c.tags.first.object.should == foo_c end it "should only copy #copyable_attributes" do foo = MethodObject.new(:root, :foo) foo.should_receive(:copyable_attributes).and_return %w(a b c) foo.should_receive(:instance_variable_get).with('@a').and_return(1) foo.should_receive(:instance_variable_get).with('@b').and_return(2) foo.should_receive(:instance_variable_get).with('@c').and_return(3) bar = MethodObject.new(:root, :bar) bar.should_receive(:instance_variable_set).with('@a', 1) bar.should_receive(:instance_variable_set).with('@b', 2) bar.should_receive(:instance_variable_set).with('@c', 3) foo.copy_to(bar) end end end yard-0.8.7.3/spec/code_objects/macro_object_spec.rb0000644000004100000410000001022312261240652022217 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::CodeObjects::MacroObject do before do Registry.clear end describe '.create' do def create(*args) MacroObject.create(*args) end it "should create an object" do create('foo', '') obj = Registry.at('.macro.foo') obj.should_not be_nil end it "should use identity map" do obj1 = create('foo', '') obj2 = create('foo', '') obj1.object_id.should == obj2.object_id end it "should allow specifying of macro data" do obj = create('foo', 'MACRODATA') obj.macro_data.should == 'MACRODATA' end it "should attach if a method object is provided" do obj = create('foo', 'MACRODATA', P('Foo.property')) obj.method_object.should == P('Foo.property') obj.should be_attached end end describe '.find' do before { MacroObject.create('foo', 'DATA') } it "should search for an object by name" do MacroObject.find('foo').macro_data.should == 'DATA' end it "should accept Symbol" do MacroObject.find(:foo).macro_data.should == 'DATA' end end describe '.find_or_create' do it "should look up name if @!macro is present and find object" do macro1 = MacroObject.create('foo', 'FOO') macro2 = MacroObject.find_or_create('foo', "a b c") macro1.should == macro2 end it "should create new macro if macro by that name does not exist" do MacroObject.find_or_create('foo', "@!method $1") MacroObject.find('foo').macro_data.should == "@!method $1" end end describe '.apply' do before do @args = %w(foo a b c) end def apply(comments) MacroObject.apply(comments, @args) end it "should only expand macros if @macro is present" do apply("$1$2$3").should == "$1$2$3" end it "should handle macro text inside block" do apply("@!macro\n foo$1$2$3\nfoobaz").should == "fooabc\nfoobaz" end it "should append docstring to existing macro" do macro = MacroObject.create('name', '$3$2$1') result = MacroObject.apply("@!macro name\nfoobar", @args) result.should == "cba\nfoobar" end it "should use only non macro data if docstring is an existing macro" do data = "@!macro name\n $3$2$1\nEXTRA" result = MacroObject.apply(data, @args, 'SOURCE') result.should == "cba\nEXTRA" MacroObject.apply("@!macro name\nFOO", @args).should == "cba\nFOO" end it "should create macros if they don't exist" do result = MacroObject.apply("@!macro name\n foo!$1", @args, 'SOURCE') result.should == "foo!a" MacroObject.find('name').macro_data.should == 'foo!$1' end it "should keep other tags" do apply("@!macro\n foo$1$2$3\n@param name foo\nfoo").should == "fooabc\nfoo\n@param name\n foo" end end describe '.expand' do def expand(comments) args = %w(foo a b c) full_line = 'foo :bar, :baz' MacroObject.expand(comments, args, full_line) end it "should allow escaping of macro syntax" do expand("$1\\$2$3").should == "a$2c" end it "should replace $* with the whole statement" do expand("$* ${*}").should == "foo :bar, :baz foo :bar, :baz" end it "should replace $0 with method name" do expand("$0 ${0}").should == "foo foo" end it "should replace all $N values with the Nth argument in the method call" do expand("$1$2$3${3}\nfoobar").should == "abcc\nfoobar" end it "should replace ${N-M} ranges with N-M arguments (incl. commas)" do expand("${1-2}x").should == "a, bx" end it "should handle open ended ranges (${N-})" do expand("${2-}").should == "b, c" end it "should handle negative indexes ($-N)" do expand("$-1 ${-2-} ${-2--2}").should == "c b, c b" end it "should accept Docstring objects" do expand(Docstring.new("$1\n@param name foo")).should == "a\n@param name foo" end end describe '#expand' do it "should expand macro given its data" do macro = MacroObject.create_docstring('foo', '$1 $2 THREE!') macro.expand(['NAME', 'ONE', 'TWO']).should == "ONE TWO THREE!" end end end yard-0.8.7.3/spec/code_objects/namespace_object_spec.rb0000644000004100000410000001260012261240652023053 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::CodeObjects::NamespaceObject do before { Registry.clear } describe '#child' do it "should return the object matching the name passed in if argument is a Symbol" do obj = NamespaceObject.new(nil, :YARD) other = NamespaceObject.new(obj, :Other) obj.child(:Other).should == other obj.child('Other').should == other end it "should look for attributes matching the object if the argument is a Hash" do obj = NamespaceObject.new(nil, :YARD) NamespaceObject.new(obj, :NotOther) other = NamespaceObject.new(obj, :Other) other.somevalue = 2 obj.child(:somevalue => 2).should == other end end describe '#meths' do it "should return #meths even if parent is a Proxy" do obj = NamespaceObject.new(P(:String), :YARD) obj.meths.should be_empty end it "should not list included methods that are already defined in the namespace using #meths" do a = ModuleObject.new(nil, :Mod1) ameth = MethodObject.new(a, :testing) b = ModuleObject.new(nil, :Mod2) bmeth = MethodObject.new(b, :foo) c = NamespaceObject.new(nil, :YARD) cmeth = MethodObject.new(c, :testing) cmeth2 = MethodObject.new(c, :foo) c.instance_mixins << a c.class_mixins << b meths = c.meths meths.should include(bmeth) meths.should include(cmeth) meths.should include(cmeth2) meths.should_not include(ameth) meths = c.included_meths meths.should include(bmeth) meths.should_not include(ameth) meths.should_not include(cmeth) meths.should_not include(cmeth2) end end describe '#included_meths' do it "should list methods mixed into the class scope as class methods" do b = ModuleObject.new(nil, :Mod2) bmeth = MethodObject.new(b, :foo) bmeth2 = MethodObject.new(b, :foo2) c = NamespaceObject.new(nil, :YARD) c.class_mixins << b [bmeth, bmeth2].each {|o| o.scope.should == :instance } meths = c.included_meths(:scope => :class) meths.each {|o| o.scope.should == :class } end it "should not list methods overridden by another included module" do a = ModuleObject.new(nil, :Mod) ameth = MethodObject.new(a, :testing) b = ModuleObject.new(nil, :Mod2) bmeth = MethodObject.new(b, :testing) c = NamespaceObject.new(nil, :YARD) c.instance_mixins.unshift a c.instance_mixins.unshift b c.class_mixins.unshift b c.class_mixins.unshift a meths = c.included_meths(:scope => :instance) meths.should_not include(ameth) meths.should include(bmeth) meths = c.included_meths(:scope => :class) meths.should include(ameth) meths.should_not include(bmeth) end end describe '#class_attributes' do it "should list class attributes" do a = NamespaceObject.new(nil, :Mod) a.attributes[:instance][:a] = { :read => MethodObject.new(a, :a), :write => nil } a.attributes[:instance][:b] = { :read => MethodObject.new(a, :b), :write => nil } a.attributes[:class][:a] = { :read => MethodObject.new(a, :a, :class), :write => nil } a.class_attributes.keys.should include(:a) a.class_attributes.keys.should_not include(:b) end end describe '#instance_attributes' do it "should list instance attributes" do a = NamespaceObject.new(nil, :Mod) a.attributes[:instance][:a] = { :read => MethodObject.new(a, :a), :write => nil } a.attributes[:instance][:b] = { :read => MethodObject.new(a, :b), :write => nil } a.attributes[:class][:a] = { :read => MethodObject.new(a, :a, :class), :write => nil } a.instance_attributes.keys.should include(:a) a.instance_attributes.keys.should include(:b) end end describe '#constants/#included_constants' do before do Registry.clear YARD.parse_string <<-eof module A CONST1 = 1 CONST2 = 2 end module B CONST2 = -2 CONST3 = -3 end class C CONST3 = 3 CONST4 = 4 include A include B end eof end it "should list all included constants by default" do consts = P(:C).constants consts.should include(P('A::CONST1')) consts.should include(P('C::CONST4')) end it "should allow :included to be set to false to ignore included constants" do consts = P(:C).constants(:included => false) consts.should_not include(P('A::CONST1')) consts.should include(P('C::CONST4')) end it "should not list an included constant if it is defined in the object" do consts = P(:C).constants consts.should include(P('C::CONST3')) consts.should_not include(P('B::CONST3')) end it "should not list an included constant if it is shadowed by another included constant" do consts = P(:C).included_constants consts.should include(P('B::CONST2')) consts.should_not include(P('A::CONST2')) end end describe '#included_meths' do it "should return all included methods with :all = true" do YARD.parse_string <<-eof module B; def foo; end end module C; def bar; end end class A; include B; include C; def foo; end; def bar; end end eof Registry.at('A').included_meths(:all => true).should == [P('C#bar'), P('B#foo')] end end end yard-0.8.7.3/spec/registry_store_spec.rb0000644000004100000410000002776112261240652020250 0ustar www-datawww-datarequire File.join(File.dirname(__FILE__), "spec_helper") describe YARD::RegistryStore do before do FileUtils.rm_rf("foo") @store = RegistryStore.new @serializer = Serializers::YardocSerializer.new('foo') @foo = CodeObjects::MethodObject.new(nil, :foo) @bar = CodeObjects::ClassObject.new(nil, :Bar) Serializers::YardocSerializer.stub!(:new).and_return(@serializer) end describe '#load' do it "should load root.dat as full object list if it is a Hash" do File.should_receive(:directory?).with('foo').and_return(true) File.should_receive(:file?).with('foo/checksums').and_return(false) File.should_receive(:file?).with('foo/proxy_types').and_return(false) File.should_receive(:file?).with('foo/object_types').and_return(false) @serializer.should_receive(:deserialize).with('root').and_return({:root => @foo, :A => @bar}) @store.load('foo').should == true @store.root.should == @foo @store.get('A').should == @bar end it "should load old yardoc format if .yardoc is a file" do File.should_receive(:directory?).with('foo').and_return(false) File.should_receive(:file?).with('foo').and_return(true) File.should_receive(:read_binary).with('foo').and_return('FOO') Marshal.should_receive(:load).with('FOO') @store.load('foo') end it "should load new yardoc format if .yardoc is a directory" do File.should_receive(:directory?).with('foo').and_return(true) File.should_receive(:file?).with('foo/checksums').and_return(false) File.should_receive(:file?).with('foo/proxy_types').and_return(false) File.should_receive(:file?).with('foo/object_types').and_return(false) File.should_receive(:file?).with('foo/objects/root.dat').and_return(false) @store.load('foo').should == true end it "should return true if .yardoc is loaded (file)" do File.should_receive(:directory?).with('myyardoc').and_return(false) File.should_receive(:file?).with('myyardoc').and_return(true) File.should_receive(:read_binary).with('myyardoc').and_return(Marshal.dump('')) @store.load('myyardoc').should == true end it "should return true if .yardoc is loaded (directory)" do File.should_receive(:directory?).with('foo').and_return(true) File.should_receive(:file?).with('foo/checksums').and_return(false) File.should_receive(:file?).with('foo/proxy_types').and_return(false) File.should_receive(:file?).with('foo/object_types').and_return(false) File.should_receive(:file?).with('foo/objects/root.dat').and_return(false) @store.load('foo').should == true end it "should return false if .yardoc does not exist" do @store.load('NONEXIST').should == false end it "should return false if there is no file to load" do @store.load(nil).should == false end it "should load checksums if they exist" do File.should_receive(:directory?).with('foo').and_return(true) File.should_receive(:file?).with('foo/checksums').and_return(true) File.should_receive(:file?).with('foo/proxy_types').and_return(false) File.should_receive(:file?).with('foo/objects/root.dat').and_return(false) File.should_receive(:file?).with('foo/object_types').and_return(false) File.should_receive(:readlines).with('foo/checksums').and_return([ 'file1 CHECKSUM1', ' file2 CHECKSUM2 ' ]) @store.load('foo').should == true @store.checksums.should == {'file1' => 'CHECKSUM1', 'file2' => 'CHECKSUM2'} end it "should load proxy_types if they exist" do File.should_receive(:directory?).with('foo').and_return(true) File.should_receive(:file?).with('foo/checksums').and_return(false) File.should_receive(:file?).with('foo/proxy_types').and_return(true) File.should_receive(:file?).with('foo/object_types').and_return(false) File.should_receive(:file?).with('foo/objects/root.dat').and_return(false) File.should_receive(:read_binary).with('foo/proxy_types').and_return(Marshal.dump({'a' => 'b'})) @store.load('foo').should == true @store.proxy_types.should == {'a' => 'b'} end it "should load root object if it exists" do File.should_receive(:directory?).with('foo').and_return(true) File.should_receive(:file?).with('foo/checksums').and_return(false) File.should_receive(:file?).with('foo/proxy_types').and_return(false) File.should_receive(:file?).with('foo/object_types').and_return(false) File.should_receive(:file?).with('foo/objects/root.dat').and_return(true) File.should_receive(:read_binary).with('foo/objects/root.dat').and_return(Marshal.dump(@foo)) @store.load('foo').should == true @store.root.should == @foo end end describe '#save' do before do @store.stub!(:write_proxy_types) @store.stub!(:write_checksums) @store.stub!(:destroy) end after do Registry.single_object_db = nil end def saves_to_singledb @serializer.should_receive(:serialize).once.with(instance_of(Hash)) @store.save(true, 'foo') end def add_items(n) n.times {|i| @store[i.to_s] = @foo } end def saves_to_multidb times = @store.keys.size @serializer.should_receive(:serialize).exactly(times).times @store.save(true, 'foo') @last = times end it "should save as single object db if single_object_db is nil and there are less than 3000 objects" do Registry.single_object_db = nil add_items(100) saves_to_singledb end it "should save as single object db if single_object_db is nil and there are more than 3000 objects" do Registry.single_object_db = nil add_items(5000) saves_to_singledb end it "should save as single object db if single_object_db is true (and any amount of objects)" do Registry.single_object_db = true add_items(100) saves_to_singledb add_items(5000) saves_to_singledb end it "should never save as single object db if single_object_db is false" do Registry.single_object_db = false add_items(100) saves_to_multidb add_items(5000) saves_to_multidb end end describe '#put' do it "should assign values" do @store.put(:YARD, @foo) @store.get(:YARD).should == @foo end it "should treat '' as root" do @store.put('', @foo) @store.get(:root).should == @foo end end describe '#get' do it "should hit cache if object exists" do @store.put(:YARD, @foo) @store.get(:YARD).should == @foo end it "should hit backstore on cache miss and cache is not fully loaded" do serializer = mock(:serializer) serializer.should_receive(:deserialize).once.with(:YARD).and_return(@foo) @store.load('foo') @store.instance_variable_set("@loaded_objects", 0) @store.instance_variable_set("@available_objects", 100) @store.instance_variable_set("@serializer", serializer) @store.get(:YARD).should == @foo @store.get(:YARD).should == @foo @store.instance_variable_get("@loaded_objects").should == 1 end end [:keys, :values].each do |item| describe "##{item}" do it "should load entire database if reload=true" do File.should_receive(:directory?).with('foo').and_return(true) @store.load('foo') @store.should_receive(:load_all) @store.send(item, true) end it "should not load entire database if reload=false" do File.should_receive(:directory?).with('foo').and_return(true) @store.load('foo') @store.should_not_receive(:load_all) @store.send(item, false) end end end describe '#paths_for_type' do after { Registry.clear } it "should set all object types if not set by object_types" do File.should_receive(:directory?).with('foo').and_return(true) File.should_receive(:file?).with('foo/checksums').and_return(false) File.should_receive(:file?).with('foo/proxy_types').and_return(false) File.should_receive(:file?).with('foo/object_types').and_return(false) @serializer.should_receive(:deserialize).with('root').and_return({:'A#foo' => @foo, :A => @bar}) @store.load('foo') @store.paths_for_type(:method).should == ['#foo'] @store.paths_for_type(:class).should == ['Bar'] end it "should keep track of types when assigning values" do @store.put(:abc, @foo) @store.paths_for_type(@foo.type).should == ['abc'] end it "should reassign path if type changes" do foo = CodeObjects::ClassObject.new(:root, :Foo) @store.put('Foo', foo) @store.get('Foo').type.should == :class @store.paths_for_type(:class).should == ["Foo"] foo = CodeObjects::ModuleObject.new(:root, :Foo) @store.put('Foo', foo) @store.get('Foo').type.should == :module @store.paths_for_type(:class).should == [] @store.paths_for_type(:module).should == ["Foo"] end end describe '#values_for_type' do it "should return all objects with type" do @store.put(:abc, @foo) @store.values_for_type(@foo.type).should == [@foo] end end describe '#load_all' do it "should load the entire database" do foomock = mock(:Foo) barmock = mock(:Bar) foomock.stub!(:type).and_return(:class) barmock.stub!(:type).and_return(:class) foomock.should_receive(:path).and_return('Foo') barmock.should_receive(:path).and_return('Bar') File.should_receive(:directory?).with('foo').and_return(true) File.should_receive(:file?).with('foo/proxy_types').and_return(false) File.should_receive(:file?).with('foo/object_types').and_return(false) File.should_receive(:file?).with('foo/checksums').and_return(false) File.should_receive(:file?).with('foo/objects/root.dat').and_return(false) @store.should_receive(:all_disk_objects).at_least(1).times.and_return(['foo/objects/foo', 'foo/objects/bar']) @store.load('foo') serializer = @store.instance_variable_get("@serializer") serializer.should_receive(:deserialize).with('foo/objects/foo', true).and_return(foomock) serializer.should_receive(:deserialize).with('foo/objects/bar', true).and_return(barmock) @store.send(:load_all) @store.instance_variable_get("@available_objects").should == 2 @store.instance_variable_get("@loaded_objects").should == 2 @store[:Foo].should == foomock @store[:Bar].should == barmock end end describe '#destroy' do it "should destroy file ending in .yardoc when force=false" do File.should_receive(:file?).with('foo.yardoc').and_return(true) File.should_receive(:unlink).with('foo.yardoc') @store.instance_variable_set("@file", 'foo.yardoc') @store.destroy.should == true end it "should destroy dir ending in .yardoc when force=false" do File.should_receive(:directory?).with('foo.yardoc').and_return(true) FileUtils.should_receive(:rm_rf).with('foo.yardoc') @store.instance_variable_set("@file", 'foo.yardoc') @store.destroy.should == true end it "should not destroy file/dir not ending in .yardoc when force=false" do File.should_not_receive(:file?).with('foo') File.should_not_receive(:directory?).with('foo') File.should_not_receive(:unlink).with('foo') FileUtils.should_not_receive(:rm_rf).with('foo') @store.instance_variable_set("@file", 'foo') @store.destroy.should == false end it "should destroy any file/dir when force=true" do File.should_receive(:file?).with('foo').and_return(true) File.should_receive(:unlink).with('foo') @store.instance_variable_set("@file", 'foo') @store.destroy(true).should == true end end describe '#locale' do it "should load ./po/LOCALE_NAME.po" do fr_locale = I18n::Locale.new("fr") I18n::Locale.should_receive(:new).with("fr").and_return(fr_locale) Registry.should_receive(:po_dir).and_return("po") fr_locale.should_receive(:load).with("po") @store.locale("fr").should == fr_locale end end end yard-0.8.7.3/spec/registry_spec.rb0000644000004100000410000003273412261240652017030 0ustar www-datawww-datarequire File.join(File.dirname(__FILE__), "spec_helper") include CodeObjects require "thread" describe YARD::Registry do before { Registry.clear } describe '.yardoc_file_for_gem' do before do @gem = mock('gem') @gem.stub!(:name).and_return('foo') @gem.stub!(:full_name).and_return('foo-1.0') @gem.stub!(:full_gem_path).and_return('/path/to/foo') end it "should return nil if gem isn't found" do Gem.source_index.should_receive(:find_name).with('foo', '>= 0').and_return([]) Registry.yardoc_file_for_gem('foo').should == nil end it "should allow version to be specified" do Gem.source_index.should_receive(:find_name).with('foo', '= 2').and_return([]) Registry.yardoc_file_for_gem('foo', '= 2').should == nil end it "should return existing .yardoc path for gem when for_writing=false" do File.should_receive(:exist?).and_return(false) File.should_receive(:exist?).with('/path/to/foo/.yardoc').and_return(true) Gem.source_index.should_receive(:find_name).with('foo', '>= 0').and_return([@gem]) Registry.yardoc_file_for_gem('foo').should == '/path/to/foo/.yardoc' end it "should return nil if no .yardoc path exists in gem when for_writing=false" do File.should_receive(:exist?).and_return(false) File.should_receive(:exist?).with('/path/to/foo/.yardoc').and_return(false) Gem.source_index.should_receive(:find_name).with('foo', '>= 0').and_return([@gem]) Registry.yardoc_file_for_gem('foo').should == nil end it "should search local gem path first if for_writing=false" do File.should_receive(:exist?).and_return(true) Gem.source_index.should_receive(:find_name).with('foo', '>= 0').and_return([@gem]) Registry.yardoc_file_for_gem('foo').should =~ %r{/.yard/gem_index/foo-1.0.yardoc$} end it "should return global .yardoc path for gem if for_writing=true and dir is writable" do File.should_receive(:writable?).with(@gem.full_gem_path).and_return(true) Gem.source_index.should_receive(:find_name).with('foo', '>= 0').and_return([@gem]) Registry.yardoc_file_for_gem('foo', '>= 0', true).should == '/path/to/foo/.yardoc' end it "should return local .yardoc path for gem if for_writing=true and dir is not writable" do File.should_receive(:writable?).with(@gem.full_gem_path).and_return(false) Gem.source_index.should_receive(:find_name).with('foo', '>= 0').and_return([@gem]) Registry.yardoc_file_for_gem('foo', '>= 0', true).should =~ %r{/.yard/gem_index/foo-1.0.yardoc$} end it "should return gem path if gem starts with yard-doc- and for_writing=false" do @gem.stub!(:name).and_return('yard-doc-core') @gem.stub!(:full_name).and_return('yard-doc-core-1.0') @gem.stub!(:full_gem_path).and_return('/path/to/yard-doc-core') Gem.source_index.should_receive(:find_name).with('yard-doc-core', '>= 0').and_return([@gem]) File.should_receive(:exist?).with('/path/to/yard-doc-core/.yardoc').and_return(true) Registry.yardoc_file_for_gem('yard-doc-core').should == '/path/to/yard-doc-core/.yardoc' end it "should return nil if gem starts with yard-doc- and for_writing=true" do @gem.stub!(:name).and_return('yard-doc-core') @gem.stub!(:full_name).and_return('yard-doc-core-1.0') @gem.stub!(:full_gem_path).and_return('/path/to/yard-doc-core') Gem.source_index.should_receive(:find_name).with('yard-doc-core', '>= 0').and_return([@gem]) File.should_receive(:exist?).with('/path/to/yard-doc-core/.yardoc').and_return(true) Registry.yardoc_file_for_gem('yard-doc-core', '>= 0', true).should == nil end end describe '.root' do it "should have an empty path for root" do Registry.root.path.should == "" end end describe '.locale' do it "should load locale object" do fr_locale = I18n::Locale.new("fr") store = Registry.send(:thread_local_store) store.should_receive(:locale).with("fr").and_return(fr_locale) Registry.locale("fr").should == fr_locale end end describe '.resolve' do it "should resolve any existing namespace" do o1 = ModuleObject.new(:root, :A) o2 = ModuleObject.new(o1, :B) o3 = ModuleObject.new(o2, :C) Registry.resolve(o1, "B::C").should == o3 Registry.resolve(:root, "A::B::C") end it "should resolve an object in the root namespace when prefixed with ::" do o1 = ModuleObject.new(:root, :A) o2 = ModuleObject.new(o1, :B) o3 = ModuleObject.new(o2, :C) Registry.resolve(o3, "::A").should == o1 Registry.resolve(o3, "::String", false, true).should == P(:String) end it "should resolve instance methods with # prefix" do o1 = ModuleObject.new(:root, :A) o2 = ModuleObject.new(o1, :B) o3 = ModuleObject.new(o2, :C) o4 = MethodObject.new(o3, :methname) Registry.resolve(o1, "B::C#methname").should == o4 Registry.resolve(o2, "C#methname").should == o4 Registry.resolve(o3, "#methname").should == o4 end it "should resolve instance methods in the root without # prefix" do o = MethodObject.new(:root, :methname) Registry.resolve(:root, 'methname').should == o end it "should resolve superclass methods when inheritance = true" do superyard = ClassObject.new(:root, :SuperYard) yard = ClassObject.new(:root, :YARD) yard.superclass = superyard imeth = MethodObject.new(superyard, :hello) cmeth = MethodObject.new(superyard, :class_hello, :class) Registry.resolve(yard, "#hello", false).should be_nil Registry.resolve(yard, "#hello", true).should == imeth Registry.resolve(yard, "class_hello", false).should be_nil Registry.resolve(yard, "class_hello", true).should == cmeth end it "should resolve mixin methods when inheritance = true" do yard = ClassObject.new(:root, :YARD) mixin = ModuleObject.new(:root, :Mixin) yard.mixins(:instance) << mixin imeth = MethodObject.new(mixin, :hello) cmeth = MethodObject.new(mixin, :class_hello, :class) Registry.resolve(yard, "#hello", false).should be_nil Registry.resolve(yard, "#hello", true).should == imeth Registry.resolve(yard, "class_hello", false).should be_nil Registry.resolve(yard, "class_hello", true).should == cmeth end it "should resolve methods in Object when inheritance = true" do YARD.parse_string <<-eof class Object; def foo; end end class A; end class MyObject < A; end eof Registry.resolve(P('MyObject'), '#foo', true).should == P('Object#foo') end it "should resolve methods in BasicObject when inheritance = true" do YARD.parse_string <<-eof class BasicObject; def foo; end end class A; end class MyObject < A; end eof Registry.resolve(P('MyObject'), '#foo', true).should == P('BasicObject#foo') end it "should not resolve methods in Object if inheriting BasicObject when inheritance = true" do YARD.parse_string <<-eof class Object; def foo; end end class MyObject < BasicObject; end eof Registry.resolve(P('MyObject'), '#foo', true).should be_nil end it "should allow type=:typename to ensure resolved object is of a certain type" do YARD.parse_string "class Foo; end" Registry.resolve(Registry.root, 'Foo').should == Registry.at('Foo') Registry.resolve(Registry.root, 'Foo', false, false, :method).should be_nil end it "should allow keep trying to find obj where type equals object type" do YARD.parse_string <<-eof module Foo class Bar; end def self.Bar; end end eof Registry.resolve(P('Foo'), 'Bar').should == Registry.at('Foo::Bar') Registry.resolve(P('Foo'), 'Bar', false, false, :method).should == Registry.at('Foo.Bar') end it "should return proxy fallback with given type if supplied" do YARD.parse_string "module Foo; end" proxy = Registry.resolve(P('Foo'), 'Bar', false, true, :method) proxy.type.should == :method proxy = Registry.resolve(P('Qux'), 'Bar', false, true, :method) proxy.type.should == :method end it "should only check 'Path' in lookup on root namespace" do Registry.should_receive(:at).once.with('Test').and_return(true) Registry.resolve(Registry.root, "Test") end it "should not perform lookup by joining namespace and name without separator" do yard = ClassObject.new(:root, :YARD) Registry.should_not_receive(:at).with('YARDB') Registry.resolve(yard, 'B') end end describe '.all' do it "should return objects of types specified by arguments" do ModuleObject.new(:root, :A) o1 = ClassObject.new(:root, :B) o2 = MethodObject.new(:root, :testing) r = Registry.all(:method, :class) r.should include(o1, o2) end it "should return code objects" do o1 = ModuleObject.new(:root, :A) o2 = ClassObject.new(:root, :B) MethodObject.new(:root, :testing) r = Registry.all.select {|t| NamespaceObject === t } r.should include(o1, o2) end it "should allow .all to omit list" do o1 = ModuleObject.new(:root, :A) o2 = ClassObject.new(:root, :B) r = Registry.all r.should include(o1, o2) end end describe '.paths' do it "should return all object paths" do o1 = ModuleObject.new(:root, :A) o2 = ClassObject.new(:root, :B) Registry.paths.should include('A', 'B') end end describe '.load_yardoc' do it "should delegate load to RegistryStore" do store = RegistryStore.new store.should_receive(:load).with('foo') RegistryStore.should_receive(:new).and_return(store) Registry.yardoc_file = 'foo' Registry.load_yardoc end it "should return itself" do Registry.load_yardoc.should == Registry end it "should maintain hash key equality on loaded objects" do Registry.clear Registry.load!(File.dirname(__FILE__) + '/serializers/data/serialized_yardoc') baz = Registry.at('Foo#baz') Registry.at('Foo').aliases.keys.should include(baz) Registry.at('Foo').aliases.has_key?(baz).should == true end end ['load', 'load_all', 'load!'].each do |meth| describe('.' + meth) do it "should return itself" do Registry.send(meth).should == Registry end end end describe '.each' do before do YARD.parse_string "def a; end; def b; end; def c; end" end after { Registry.clear } it "should iterate over .all" do items = [] Registry.each {|x| items << x.path } items.sort.should == ['#a', '#b', '#c'] end it "should include Enumerable and allow for find, select" do Registry.find {|x| x.path == "#a" }.should be_a(CodeObjects::MethodObject) end end describe '.instance' do it "should return itself" do Registry.instance.should == Registry end end describe '.single_object_db' do it "should default to nil" do Registry.single_object_db.should == nil Thread.new { Registry.single_object_db.should == nil }.join end end describe 'Thread local' do it "should maintain two Registries in separate threads" do barrier = 0 mutex = Mutex.new threads = [] threads << Thread.new do Registry.clear YARD.parse_string "# docstring 1\nclass Foo; end" mutex.synchronize { barrier += 1 } while barrier < 2 do s = "barrier < 2, spinning" end Registry.at('Foo').docstring.should == "docstring 1" end threads << Thread.new do Registry.clear YARD.parse_string "# docstring 2\nclass Foo; end" mutex.synchronize { barrier += 1 } while barrier < 2 do s = "barrier < 2, spinning" end Registry.at('Foo').docstring.should == "docstring 2" end threads.each {|t| t.join } end it "should allow setting of yardoc_file in separate threads" do barrier = 0 mutex = Mutex.new threads = [] threads << Thread.new do Registry.yardoc_file.should == '.yardoc' Registry.yardoc_file = 'foo' mutex.synchronize { barrier += 1 } while barrier == 1 do s = "barrier = 1, spinning" end Registry.yardoc_file.should == 'foo' end threads << Thread.new do while barrier == 0 do s = "barrier = 0, spinning" end Registry.yardoc_file.should == '.yardoc' mutex.synchronize { barrier += 1 } Registry.yardoc_file = 'foo2' end threads.each {|t| t.join } Registry.yardoc_file = Registry::DEFAULT_YARDOC_FILE end it "should automatically clear in new threads" do Thread.new { Registry.all.should be_empty }.join end it "should allow setting of po_dir in separate threads" do barrier = 0 mutex = Mutex.new threads = [] threads << Thread.new do Registry.po_dir.should == 'po' Registry.po_dir = 'locale' mutex.synchronize { barrier += 1 } while barrier == 1 do s = "barrier = 1, spinning" end Registry.po_dir.should == 'locale' end threads << Thread.new do while barrier == 0 do s = "barrier = 0, spinning" end Registry.po_dir.should == 'po' mutex.synchronize { barrier += 1 } Registry.po_dir = '.' end threads.each {|t| t.join } Registry.po_dir = Registry::DEFAULT_PO_DIR end end end yard-0.8.7.3/spec/verifier_spec.rb0000644000004100000410000000607212261240652016767 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/spec_helper' describe YARD::Verifier do describe '#parse_expressions' do it "should create #__execute method" do v = Verifier.new("expr1") v.should respond_to(:__execute) end it "should parse @tagname into tag('tagname')" do obj = mock(:object) obj.should_receive(:tag).with('return') Verifier.new('@return').call(obj) end it "should parse @@tagname into object.tags('tagname')" do obj = mock(:object) obj.should_receive(:tags).with('return') Verifier.new('@@return').call(obj) end it "should allow namespaced tag using @{} syntax" do obj = mock(:object) obj.should_receive(:tag).with('yard.return') Verifier.new('@{yard.return}').call(obj) end it "should allow namespaced tags using @{} syntax" do obj = mock(:object) obj.should_receive(:tags).with('yard.return') Verifier.new('@@{yard.return}').call(obj) end it "should call methods on tag object" do obj = mock(:object) obj2 = mock(:tag) obj.should_receive(:tag).with('return').and_return obj2 obj2.should_receive(:foo) Verifier.new('@return.foo').call(obj) end it "should send any missing methods to object" do obj = mock(:object) obj.should_receive(:has_tag?).with('return') Verifier.new('has_tag?("return")').call(obj) end it "should allow multiple expressions" do obj = mock(:object) obj.should_receive(:tag).with('return').and_return(true) obj.should_receive(:tag).with('param').and_return(false) Verifier.new('@return', '@param').call(obj).should == false end end describe '#o' do it "should alias object to o" do obj = mock(:object) obj.should_receive(:a).ordered Verifier.new('o.a').call(obj) end end describe '#call' do it "should mock a nonexistent tag so that exceptions are not raised" do obj = mock(:object) obj.should_receive(:tag).and_return(nil) Verifier.new('@return.text').call(obj).should == false end it "should not fail if no expressions were added" do lambda { Verifier.new.call(nil) }.should_not raise_error end it "should always ignore proxy objects and return true" do v = Verifier.new('tag(:x)') lambda { v.call(P('foo')).should == true }.should_not raise_error end end describe '#expressions' do it "should maintain a list of all unparsed expressions" do Verifier.new('@return.text', '@private').expressions.should == ['@return.text', '@private'] end end describe '#expressions=' do it "should recompile expressions when attribute is modified" do obj = mock(:object) obj.should_receive(:tag).with('return') v = Verifier.new v.expressions = ['@return'] v.call(obj) end end describe '#add_expressions' do it "should add new expressions and recompile" do obj = mock(:object) obj.should_receive(:tag).with('return') v = Verifier.new v.add_expressions '@return' v.call(obj) end end endyard-0.8.7.3/spec/cli/0000755000004100000410000000000012261240652014357 5ustar www-datawww-datayard-0.8.7.3/spec/cli/command_parser_spec.rb0000644000004100000410000000240012261240652020704 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::CLI::CommandParser do describe '#run' do before do @cmd = CLI::CommandParser.new end it "should show help if --help is provided" do command = mock(:command) command.should_receive(:run).with('--help') CLI::CommandParser.commands[:foo] = command @cmd.class.default_command = :foo @cmd.run *%w( foo --help ) end it "should use default command if first argument is a switch" do command = mock(:command) command.should_receive(:run).with('--a', 'b', 'c') CLI::CommandParser.commands[:foo] = command @cmd.class.default_command = :foo @cmd.run *%w( --a b c ) end it "should use default command if no arguments are provided" do command = mock(:command) command.should_receive(:run) CLI::CommandParser.commands[:foo] = command @cmd.class.default_command = :foo @cmd.run end it "should list commands if command is not found" do @cmd.should_receive(:list_commands) @cmd.run *%w( unknown_command --args ) end it "should list commands if --help is provided as sole argument" do @cmd.should_receive(:list_commands) @cmd.run *%w( --help ) end end endyard-0.8.7.3/spec/cli/server_spec.rb0000644000004100000410000002453212261240652017232 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' class Server::WebrickAdapter; def start; end end describe YARD::CLI::Server do before do CLI::Yardoc.stub!(:run) @no_verify_libraries = false @set_libraries = true @no_adapter_mock = false @libraries = {} @options = {:single_library => true, :caching => false} @server_options = {:Port => 8808} @adapter = mock(:adapter) @adapter.stub!(:setup) new_cli end after(:all) do Server::Adapter.shutdown end def new_cli @cli = subject end def rack_required begin; require 'rack'; rescue LoadError; pending "rack required for this test" end end def bundler_required begin; require 'bundler'; rescue LoadError; pending "bundler required for this test" end end def unstub_adapter @no_adapter_mock = true end def run(*args) if @set_libraries && @libraries.empty? library = Server::LibraryVersion.new( File.basename(Dir.pwd), nil, File.expand_path('.yardoc')) @libraries = {library.name => [library]} end unless @no_verify_libraries @libraries.values.each do |libs| libs.each do |lib| yfile = File.expand_path(lib.yardoc_file) File.stub!(:exist?).with(yfile).and_return(true) end end end unless @no_adapter_mock @cli.stub!(:adapter).and_return(@adapter) @adapter.should_receive(:new). with(@libraries, @options, @server_options).and_return(@adapter) @adapter.should_receive(:start) end @cli.run(*args.flatten) assert_libraries @libraries, @cli.libraries new_cli end def assert_libraries(expected_libs, actual_libs) actual_libs.should == expected_libs expected_libs.each do |name, libs| libs.each_with_index do |expected,i| actual = actual_libs[name][i] [:source, :source_path, :yardoc_file].each do |m| actual.send(m).should == expected.send(m) end end end end # Mocks the existence of a file. def mock_file(filename, content = nil) File.stub!(:exist?).with(filename).and_return(true) File.stub!(:read_binary).with(filename).and_return(content) if content filename_e = File.expand_path(filename) mock_file(filename_e) unless filename_e == filename end describe 'when .yardopts file exists' do before :each do Registry.yardoc_file = Registry::DEFAULT_YARDOC_FILE Dir.stub!(:pwd).and_return('/path/to/bar') @name = 'bar' end it "should use .yardoc as the yardoc db if .yardopts doesn't specify an alternate path" do mock_file '/path/to/bar/.yardopts', '--protected' @libraries[@name] = [Server::LibraryVersion.new(@name, nil, '/path/to/bar/.yardoc')] @libraries.values[0][0].source_path = '/path/to/bar' run end it "should use the yardoc db location specified by .yardopts" do mock_file '/path/to/bar/.yardopts', '--db foo' @libraries[@name] = [Server::LibraryVersion.new(@name, nil, '/path/to/bar/foo')] @libraries.values[0][0].source_path = '/path/to/bar' run end it "should parse .yardopts when the library list is odd" do mock_file '/path/to/bar/.yardopts', '--db foo' @libraries['a'] = [Server::LibraryVersion.new('a', nil, '/path/to/bar/foo')] @libraries.values[0][0].source_path = '/path/to/bar' run 'a' end end describe "when .yardopts file doesn't exist" do before :each do File.stub(:exist?).with(/^(.*[\\\/])?\.yardopts$/).and_return(false) end it "should default to .yardoc if no library is specified" do Dir.should_receive(:pwd).at_least(:once).and_return('/path/to/foo') @libraries['foo'] = [Server::LibraryVersion.new('foo', nil, '/path/to/foo/.yardoc')] run end it "should use .yardoc as yardoc file if library list is odd" do @libraries['a'] = [Server::LibraryVersion.new('a', nil, File.expand_path('.yardoc'))] run 'a' end it "should force multi library if more than one library is listed" do File.stub(:exist?).with('b').and_return(true) @options[:single_library] = false @libraries['a'] = [Server::LibraryVersion.new('a', nil, File.expand_path('b'))] @libraries['c'] = [Server::LibraryVersion.new('c', nil, File.expand_path('.yardoc'))] run %w(a b c) end it "should fail if specified directory does not exist" do @set_libraries = false File.stub(:exist?).with('b').and_return(false) log.should_receive(:warn).with(/Cannot find yardoc db for a: "b"/) run %w(a b) end end describe 'General options' do before do File.stub(:exist?).with(/\.yardopts$/).and_return(false) end it "should accept -m, --multi-library" do @options[:single_library] = false run '-m' run '--multi-library' end it "should accept -c, --cache" do @options[:caching] = true run '-c' run '--cache' end it "should accept -r, --reload" do @options[:incremental] = true run '-r' run '--reload' end it "should accept -d, --daemon" do @server_options[:daemonize] = true run '-d' run '--daemon' end it "should accept -B, --bind" do @server_options[:Host] = 'example.com' run '-B', 'example.com' run '--bind', 'example.com' end it "should bind address with WebRick adapter" do @server_options[:Host] = 'example.com' run '-B', 'example.com', '-a', 'webrick' run '--bind', 'example.com', '-a', 'webrick' end it "should bind address with Rack adapter" do @server_options[:Host] = 'example.com' run '-B', 'example.com', '-a', 'rack' run '--bind', 'example.com', '-a', 'rack' end it "should accept -p, --port" do @server_options[:Port] = 10 run '-p', '10' run '--port', '10' end it "should accept --docroot" do @server_options[:DocumentRoot] = Dir.pwd + '/__foo/bar' run '--docroot', '__foo/bar' end it "should accept -a webrick to create WEBrick adapter" do @cli.should_receive(:adapter=).with(YARD::Server::WebrickAdapter) run '-a', 'webrick' end it "should accept -a rack to create Rack adapter" do rack_required @cli.should_receive(:adapter=).with(YARD::Server::RackAdapter) run '-a', 'rack' end it "should default to Rack adapter if exists on system" do rack_required @cli.should_receive(:require).with('rubygems').and_return(false) @cli.should_receive(:require).with('rack').and_return(true) @cli.should_receive(:adapter=).with(YARD::Server::RackAdapter) @cli.send(:select_adapter) end it "should fall back to WEBrick adapter if Rack is not on system" do @cli.should_receive(:require).with('rubygems').and_return(false) @cli.should_receive(:require).with('rack').and_raise(LoadError) @cli.should_receive(:adapter=).with(YARD::Server::WebrickAdapter) @cli.send(:select_adapter) end it "should accept -s, --server" do @server_options[:server] = 'thin' run '-s', 'thin' run '--server', 'thin' end it "should accept -g, --gems" do @no_verify_libraries = true @options[:single_library] = false @libraries['gem1'] = [Server::LibraryVersion.new('gem1', '1.0.0', nil, :gem)] @libraries['gem2'] = [Server::LibraryVersion.new('gem2', '1.0.0', nil, :gem)] gem1 = mock(:gem1) gem1.stub!(:name).and_return('gem1') gem1.stub!(:version).and_return('1.0.0') gem1.stub!(:full_gem_path).and_return('/path/to/foo') gem2 = mock(:gem2) gem2.stub!(:name).and_return('gem2') gem2.stub!(:version).and_return('1.0.0') gem2.stub!(:full_gem_path).and_return('/path/to/bar') specs = {'gem1' => gem1, 'gem2' => gem2} source = mock(:source_index) source.stub!(:find_name).and_return do |k, ver| k == '' ? specs.values : specs.grep(k).map {|name| specs[name] } end Gem.stub!(:source_index).and_return(source) run '-g' run '--gems' end it "should accept -G, --gemfile" do bundler_required @no_verify_libraries = true @options[:single_library] = false @libraries['gem1'] = [Server::LibraryVersion.new('gem1', '1.0.0', nil, :gem)] @libraries['gem2'] = [Server::LibraryVersion.new('gem2', '1.0.0', nil, :gem)] gem1 = mock(:gem1) gem1.stub!(:name).and_return('gem1') gem1.stub!(:version).and_return('1.0.0') gem1.stub!(:full_gem_path).and_return('/path/to/foo') gem2 = mock(:gem2) gem2.stub!(:name).and_return('gem2') gem2.stub!(:version).and_return('1.0.0') gem2.stub!(:full_gem_path).and_return('/path/to/bar') specs = {'gem1' => gem1, 'gem2' => gem2} lockfile_parser = mock(:new) lockfile_parser.stub!(:specs).and_return([gem1, gem2]) Bundler::LockfileParser.stub!(:new).and_return(lockfile_parser) File.should_receive(:exist?).at_least(2).times.with("Gemfile.lock").and_return(true) File.stub!(:read) run '-G' run '--gemfile' File.should_receive(:exist?).with("different_name.lock").and_return(true) run '--gemfile', 'different_name' end it "should warn if lockfile is not found (with -G)" do bundler_required File.should_receive(:exist?).with(/\.yardopts$/).at_least(:once).and_return(false) File.should_receive(:exist?).with('somefile.lock').and_return(false) log.should_receive(:warn).with(/Cannot find somefile.lock/) run '-G', 'somefile' end it "should error if Bundler not available (with -G)" do @cli.should_receive(:require).with('bundler').and_raise(LoadError) log.should_receive(:error).with(/Bundler not available/) run '-G' end it "should load template paths after adapter template paths" do unstub_adapter @cli.adapter = Server::WebrickAdapter run '-t', 'foo' Templates::Engine.template_paths.last.should == 'foo' end it "should load ruby code (-e) after adapter" do unstub_adapter @cli.adapter = Server::WebrickAdapter path = File.dirname(__FILE__) + '/tmp.adapterscript.rb' begin File.open(path, 'w') do |f| f.puts "YARD::Templates::Engine.register_template_path 'foo'" f.flush run '-e', f.path Templates::Engine.template_paths.last.should == 'foo' end ensure File.unlink(path) end end end end yard-0.8.7.3/spec/cli/help_spec.rb0000644000004100000410000000115712261240652016652 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::CLI::Help do describe '#run' do it "should accept 'help command'" do CLI::Yardoc.should_receive(:run).with('--help') CLI::Help.run('doc') end it "should accept no arguments (lists all commands)" do CLI::CommandParser.should_receive(:run).with('--help') CLI::Help.run end it "should show all commands if command isn't found" do CLI::CommandParser.should_receive(:run).with('--help') help = CLI::Help.new log.should_receive(:puts).with(/not found/) help.run('unknown') end end endyard-0.8.7.3/spec/cli/gems_spec.rb0000644000004100000410000000633612261240652016661 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' require 'ostruct' require 'rubygems' describe YARD::CLI::Gems do before do @rebuild = false @gem1 = build_mock('gem1') @gem2 = build_mock('gem2') @gem3 = build_mock('gem3') end def build_mock(name, version = '1.0') OpenStruct.new :name => name, :version => version, :full_gem_path => "/path/to/gems/#{name}-#{version}", :yardoc_file => "/path/to/yardoc/#{name}-#{version}" end def build_specs(*specs) specs.each do |themock| Registry.should_receive(:yardoc_file_for_gem).with(themock.name, "= #{themock.version}").and_return(themock.yardoc_file) File.should_receive(:directory?).with(themock.yardoc_file).and_return(@rebuild) File.should_receive(:directory?).with(themock.full_gem_path).and_return(true) Registry.should_receive(:yardoc_file_for_gem).with(themock.name, "= #{themock.version}", true).and_return(themock.yardoc_file) Dir.should_receive(:chdir).with(themock.full_gem_path) end Registry.should_receive(:clear).exactly(specs.size).times CLI::Yardoc.should_receive(:run).exactly(specs.size).times end describe '#run' do it "should build all gem indexes if no gem is specified" do build_specs(@gem1, @gem2) Gem.source_index.should_receive(:find_name).with('').and_return([@gem1, @gem2]) CLI::Gems.run end it "should allow gem to be specified" do build_specs(@gem1) Gem.source_index.should_receive(:find_name).with(@gem1.name, '>= 0').and_return([@gem1]) CLI::Gems.run(@gem1.name) end it "should allow multiple gems to be specified for building" do build_specs(@gem1, @gem2) Gem.source_index.should_receive(:find_name).with(@gem1.name, @gem1.version).and_return([@gem1]) Gem.source_index.should_receive(:find_name).with(@gem2.name, '>= 0').and_return([@gem2]) CLI::Gems.run(@gem1.name, @gem1.version, @gem2.name) end it "should allow version to be specified with gem" do build_specs(@gem1) Gem.source_index.should_receive(:find_name).with(@gem1.name, '>= 1.0').and_return([@gem1]) CLI::Gems.run(@gem1.name, '>= 1.0') end it "should warn if one of the gems is not found, but it should process others" do build_specs(@gem2) Gem.source_index.should_receive(:find_name).with(@gem1.name, '>= 2.0').and_return([]) Gem.source_index.should_receive(:find_name).with(@gem2.name, '>= 0').and_return([@gem2]) log.should_receive(:warn).with(/#{@gem1.name} >= 2.0 could not be found/) CLI::Gems.run(@gem1.name, '>= 2.0', @gem2.name) end it "should fail if specified gem(s) is/are not found" do CLI::Yardoc.should_not_receive(:run) Gem.source_index.should_receive(:find_name).with(@gem1.name, '>= 2.0').and_return([]) log.should_receive(:warn).with(/#{@gem1.name} >= 2.0 could not be found/) log.should_receive(:error).with(/No specified gems could be found/) CLI::Gems.run(@gem1.name, '>= 2.0') end it "should accept --rebuild" do @rebuild = true build_specs(@gem1) Gem.source_index.should_receive(:find_name).with('').and_return([@gem1]) CLI::Gems.run('--rebuild') end end end yard-0.8.7.3/spec/cli/config_spec.rb0000644000004100000410000000511412261240652017164 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' require 'yaml' describe YARD::CLI::Config do before do @config = YARD::CLI::Config.new YARD::Config.options = YARD::Config::DEFAULT_CONFIG_OPTIONS.dup YARD::Config.stub!(:save) end def run(*args) @config.run(*args) end describe 'Listing configuration' do it "should accept --list" do opts = YARD::Config.options YAML.should_receive(:dump).twice.and_return("--- foo\nbar\nbaz") log.should_receive(:puts).twice.with("bar\nbaz") run run('--list') YARD::Config.options.should == opts end end describe 'Viewing an item' do it "should view item if no value is given" do YARD::Config.options[:foo] = 'bar' log.should_receive(:puts).with('"bar"') run 'foo' YARD::Config.options[:foo].should == 'bar' end end describe 'Modifying an item' do it "should accept --reset to set value" do YARD::Config.options[:load_plugins] = 'foo' run('--reset', 'load_plugins') YARD::Config.options[:load_plugins].should == false end it "should accept --as-list to force single item as list" do run('--as-list', 'foo', 'bar') YARD::Config.options[:foo].should == ['bar'] end it "should accept --append to append values to existing key" do YARD::Config.options[:foo] = ['bar'] run('--append', 'foo', 'baz', 'quux') YARD::Config.options[:foo].should == ['bar', 'baz', 'quux'] run('-a', 'foo', 'last') YARD::Config.options[:foo].should == ['bar', 'baz', 'quux', 'last'] end it "should turn key into list if --append is used on single item" do YARD::Config.options[:foo] = 'bar' run('-a', 'foo', 'baz') YARD::Config.options[:foo].should == ['bar', 'baz'] end it "should modify item if value is given" do run('foo', 'xxx') YARD::Config.options[:foo].should == 'xxx' end it "should turn list of values into array of values" do run('foo', 'a', 'b', '1', 'true', 'false') YARD::Config.options[:foo].should == ['a', 'b', 1, true, false] end it "should turn number into numeric Ruby type" do run('foo', '1') YARD::Config.options[:foo].should == 1 end it "should turn true into TrueClass" do run('foo', 'true') YARD::Config.options[:foo].should == true end it "should turn false into FalseClass" do run('foo', 'false') YARD::Config.options[:foo].should == false end it "should save on modification" do YARD::Config.should_receive(:save) run('foo', 'true') end end endyard-0.8.7.3/spec/cli/yri_spec.rb0000644000004100000410000000711112261240652016521 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' class TestYRI < YARD::CLI::YRI public :optparse, :find_object, :cache_object def test_stub; end def print_object(*args) test_stub; super end end describe YARD::CLI::YRI do before do @yri = TestYRI.new Registry.stub!(:load) end describe '#find_object' do it "should use cache if available" do @yri.stub!(:cache_object) File.should_receive(:exist?).with('.yardoc').and_return(false) File.should_receive(:exist?).with('bar.yardoc').and_return(true) Registry.should_receive(:load).with('bar.yardoc') Registry.should_receive(:at).ordered.with('Foo').and_return(nil) Registry.should_receive(:at).ordered.with('Foo').and_return('OBJ') @yri.instance_variable_set("@cache", {'Foo' => 'bar.yardoc'}) @yri.find_object('Foo').should == 'OBJ' end it "should never use cache ahead of current directory's .yardoc" do @yri.stub!(:cache_object) File.should_receive(:exist?).with('.yardoc').and_return(true) Registry.should_receive(:load).with('.yardoc') Registry.should_receive(:at).ordered.with('Foo').and_return(nil) Registry.should_receive(:at).ordered.with('Foo').and_return('OBJ') @yri.instance_variable_set("@cache", {'Foo' => 'bar.yardoc'}) @yri.find_object('Foo').should == 'OBJ' @yri.instance_variable_get("@search_paths")[0].should == '.yardoc' end end describe '#cache_object' do it "should skip caching for Registry.yardoc_file" do File.should_not_receive(:open).with(CLI::YRI::CACHE_FILE, 'w') @yri.cache_object('Foo', Registry.yardoc_file) end end describe '#initialize' do it "should load search paths" do path = %r{/\.yard/yri_search_paths$} File.should_receive(:file?).with(%r{/\.yard/yri_cache$}).and_return(false) File.should_receive(:file?).with(path).and_return(true) File.should_receive(:readlines).with(path).and_return(%w(line1 line2)) @yri = YARD::CLI::YRI.new spaths = @yri.instance_variable_get("@search_paths") spaths.should include('line1') spaths.should include('line2') end it "should use DEFAULT_SEARCH_PATHS prior to other paths" do YARD::CLI::YRI::DEFAULT_SEARCH_PATHS.push('foo', 'bar') path = %r{/\.yard/yri_search_paths$} File.should_receive(:file?).with(%r{/\.yard/yri_cache$}).and_return(false) File.should_receive(:file?).with(path).and_return(true) File.should_receive(:readlines).with(path).and_return(%w(line1 line2)) @yri = YARD::CLI::YRI.new spaths = @yri.instance_variable_get("@search_paths") spaths[0,4].should == %w(foo bar line1 line2) YARD::CLI::YRI::DEFAULT_SEARCH_PATHS.replace([]) end end describe '#run' do it "should search for objects and print their documentation" do obj = YARD::CodeObjects::ClassObject.new(:root, 'Foo') @yri.should_receive(:print_object).with(obj) @yri.run('Foo') Registry.clear end it "should print usage if no object is provided" do @yri.should_receive(:print_usage) @yri.should_receive(:exit).with(1) @yri.run('') end it "should print no documentation exists for object if object is not found" do STDERR.should_receive(:puts).with("No documentation for `Foo'") @yri.should_receive(:exit).with(1) @yri.run('Foo') end it "should ensure output is serialized" do obj = YARD::CodeObjects::ClassObject.new(:root, 'Foo') class << @yri def test_stub; @serializer.should_receive(:serialize).once end end @yri.run('Foo') end end end yard-0.8.7.3/spec/cli/stats_spec.rb0000644000004100000410000000471012261240652017056 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' require 'stringio' describe YARD::CLI::Stats do before do Registry.clear YARD.parse_string <<-eof class A CONST = 1 def foo; end # Documented def bar; end end module B; end eof @main_stats = "Files: 1\n" + "Modules: 1 ( 1 undocumented)\n" + "Classes: 1 ( 1 undocumented)\n" + "Constants: 1 ( 1 undocumented)\n" + "Methods: 2 ( 1 undocumented)\n" + " 20.00% documented\n" @output = StringIO.new @stats = CLI::Stats.new(false) @stats.stub!(:support_rdoc_document_file!).and_return([]) @stats.stub!(:yardopts).and_return([]) log.stub!(:puts) {|*args| @output << args.join("\n") << "\n" } end it "should list undocumented objects with --list-undoc" do @stats.run('--list-undoc') @output.string.should == <<-eof #{@main_stats} Undocumented Objects: (in file: (stdin)) B A A::CONST A#foo eof end it "should list no undocumented objects with --list-undoc when objects are undocumented" do Registry.clear YARD.parse_string <<-eof # documentation def foo; end eof @stats.run('--list-undoc') @output.string.should == "Files: 1\n" + "Modules: 0 ( 0 undocumented)\n" + "Classes: 0 ( 0 undocumented)\n" + "Constants: 0 ( 0 undocumented)\n" + "Methods: 1 ( 0 undocumented)\n" + " 100.00% documented\n" end it "should list undocumented objects in compact mode with --list-undoc --compact" do @stats.run('--list-undoc', '--compact') @output.string.should == <<-eof #{@main_stats} Undocumented Objects: B ((stdin):9) A ((stdin):1) A::CONST ((stdin):2) A#foo ((stdin):4) eof end it "should still list stats with --quiet" do @stats.run('--quiet') @output.string.should == @main_stats end it "should ignore everything with --no-public" do @stats.run('--no-public') @output.string.should == "Files: 0\n" + "Modules: 0 ( 0 undocumented)\n" + "Classes: 0 ( 0 undocumented)\n" + "Constants: 0 ( 0 undocumented)\n" + "Methods: 0 ( 0 undocumented)\n" + " 0.00% documented\n" end endyard-0.8.7.3/spec/cli/diff_spec.rb0000644000004100000410000001721712261240652016636 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' require 'stringio' require 'open-uri' describe YARD::CLI::Diff do before do CLI::Yardoc.stub!(:run) CLI::Gems.stub!(:run) @diff = CLI::Diff.new end describe 'Argument handling' do it "should exit if there is only one gem name" do @diff.should_receive(:exit) log.should_receive(:puts).with(/Usage/) @diff.run end end describe 'Diffing' do before do @objects1 = nil @objects2 = nil end def run(*args) @all_call = -1 @data = StringIO.new @objects1 ||= %w( C#fooey C#baz D.bar ) @objects2 ||= %w( A A::B A::B::C A.foo A#foo B C.foo C.bar C#baz ) @objects = [@objects1, @objects2] @diff.should_receive(:load_gem_data).ordered.with('gem1') do Registry.clear YARD.parse_string <<-eof class C def fooey; end def baz; FOO end end class D def self.bar; end end eof end @diff.should_receive(:load_gem_data).ordered.with('gem2') do Registry.clear YARD.parse_string <<-eof module A module B class C; end end def self.foo; end def foo; end end class C def self.foo; end def self.bar; end def baz; BAR end end eof end log.stub!(:print) {|data| @data << data } log.stub!(:puts) {|*args| @data << args.join("\n"); @data << "\n" } @diff.run(*(args + ['gem1', 'gem2'])) end it "should show differences between objects" do run @data.string.should == <<-eof Added objects: A ((stdin):1) (...) A::B::C ((stdin):3) C.bar ((stdin):10) C.foo ((stdin):9) Modified objects: C#baz ((stdin):3) Removed objects: C#fooey ((stdin):2) D ((stdin):5) (...) eof end it "should accept --compact" do run('--compact') @data.string.should == <<-eof A A ((stdin):1) (...) A A::B::C ((stdin):3) A C.bar ((stdin):10) A C.foo ((stdin):9) M C#baz ((stdin):3) D C#fooey ((stdin):2) D D ((stdin):5) (...) eof end it "should accept -a/--all" do ['-a', '--all'].each do |opt| run(opt) @data.string.should == <<-eof Added objects: A ((stdin):1) A#foo ((stdin):6) A.foo ((stdin):5) A::B ((stdin):2) A::B::C ((stdin):3) C.bar ((stdin):10) C.foo ((stdin):9) Modified objects: C#baz ((stdin):3) Removed objects: C#fooey ((stdin):2) D ((stdin):5) D.bar ((stdin):6) eof end end it "should accept --compact and --all" do run('--compact', '--all') @data.string.should == <<-eof A A ((stdin):1) A A#foo ((stdin):6) A A.foo ((stdin):5) A A::B ((stdin):2) A A::B::C ((stdin):3) A C.bar ((stdin):10) A C.foo ((stdin):9) M C#baz ((stdin):3) D C#fooey ((stdin):2) D D ((stdin):5) D D.bar ((stdin):6) eof end it "should accept --no-modified" do run('--compact', '--no-modified') @data.string.should == <<-eof A A ((stdin):1) (...) A A::B::C ((stdin):3) A C.bar ((stdin):10) A C.foo ((stdin):9) D C#fooey ((stdin):2) D D ((stdin):5) (...) eof end it "should accept --query" do run('--compact', '--query', 'o.type == :method') @data.string.should == <<-eof A A#foo ((stdin):6) A A.foo ((stdin):5) A C.bar ((stdin):10) A C.foo ((stdin):9) M C#baz ((stdin):3) D C#fooey ((stdin):2) D D.bar ((stdin):6) eof end end describe 'File searching' do before do @diff.stub!(:generate_yardoc) end it "should search for gem/.yardoc" do File.should_receive(:directory?).with('gem1/.yardoc').and_return(true) File.should_receive(:directory?).with('gem2/.yardoc').and_return(true) Registry.should_receive(:load_yardoc).with('gem1/.yardoc') Registry.should_receive(:load_yardoc).with('gem2/.yardoc') @diff.run('gem1', 'gem2') end it "should search for argument as yardoc" do File.should_receive(:directory?).with('gem1/.yardoc').and_return(false) File.should_receive(:directory?).with('gem2/.yardoc').and_return(false) File.should_receive(:directory?).with('gem1').and_return(true) File.should_receive(:directory?).with('gem2').and_return(true) Registry.should_receive(:load_yardoc).with('gem1') Registry.should_receive(:load_yardoc).with('gem2') @diff.run('gem1', 'gem2') end it "should search for installed gem" do File.should_receive(:directory?).with('gem1-1.0.0.gem/.yardoc').and_return(false) File.should_receive(:directory?).with('gem2-1.0.0/.yardoc').and_return(false) File.should_receive(:directory?).with('gem1-1.0.0.gem').and_return(false) File.should_receive(:directory?).with('gem2-1.0.0').and_return(false) gemmock = mock(:gemmock) spec1 = mock(:spec) spec2 = mock(:spec) gemmock.should_receive(:find_name).at_least(1).times.and_return([spec1, spec2]) Gem.should_receive(:source_index).at_least(1).times.and_return(gemmock) spec1.stub!(:full_name).and_return('gem1-1.0.0') spec1.stub!(:name).and_return('gem1') spec1.stub!(:version).and_return('1.0.0') spec2.stub!(:full_name).and_return('gem2-1.0.0') spec2.stub!(:name).and_return('gem2') spec2.stub!(:version).and_return('1.0.0') Registry.should_receive(:yardoc_file_for_gem).with('gem1', '= 1.0.0').and_return('/path/to/file') Registry.should_receive(:yardoc_file_for_gem).with('gem2', '= 1.0.0').and_return(nil) Registry.should_receive(:load_yardoc).with('/path/to/file') CLI::Gems.should_receive(:run).with('gem2', '1.0.0').and_return(nil) Dir.stub!(:chdir) @diff.run('gem1-1.0.0.gem', 'gem2-1.0.0') end it "should search for .gem file" do File.should_receive(:directory?).with('gem1/.yardoc').and_return(false) File.should_receive(:directory?).with('gem2.gem/.yardoc').and_return(false) File.should_receive(:directory?).with('gem1').and_return(false) File.should_receive(:directory?).with('gem2.gem').and_return(false) File.should_receive(:directory?).any_number_of_times File.should_receive(:exist?).with('gem1.gem').and_return(true) File.should_receive(:exist?).with('gem2.gem').and_return(true) File.should_receive(:exist?).any_number_of_times File.should_receive(:open).with('gem1.gem', 'rb') File.should_receive(:open).with('gem2.gem', 'rb') FileUtils.stub(:mkdir_p) Gem::Package.stub(:open) FileUtils.stub(:rm_rf) @diff.run('gem1', 'gem2.gem') end it "should search for .gem file on rubygems.org" do File.should_receive(:directory?).with('gem1/.yardoc').and_return(false) File.should_receive(:directory?).with('gem2.gem/.yardoc').and_return(false) File.should_receive(:directory?).with('gem1').and_return(false) File.should_receive(:directory?).with('gem2.gem').and_return(false) File.should_receive(:directory?).any_number_of_times File.should_receive(:exist?).with('gem1.gem').and_return(false) File.should_receive(:exist?).with('gem2.gem').and_return(false) File.should_receive(:exist?).any_number_of_times @diff.should_receive(:open).with('http://rubygems.org/downloads/gem1.gem') @diff.should_receive(:open).with('http://rubygems.org/downloads/gem2.gem') FileUtils.stub(:mkdir_p) Gem::Package.stub(:open) FileUtils.stub(:rm_rf) @diff.run('gem1', 'gem2.gem') end it "should error if gem is not found" do log.should_receive(:error).with("Cannot find gem gem1") log.should_receive(:error).with("Cannot find gem gem2.gem") @diff.stub!(:load_gem_data).and_return(false) @diff.run('gem1', 'gem2.gem') end end endyard-0.8.7.3/spec/cli/i18n_spec.rb0000644000004100000410000000654712261240652016511 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::CLI::I18n do before do @i18n = YARD::CLI::I18n.new @i18n.use_document_file = false @i18n.use_yardopts_file = false output_path = File.expand_path(@i18n.options.serializer.basepath) File.stub!(:open!).with(output_path, "wb") YARD.stub!(:parse) end describe 'Defaults' do before do @i18n = YARD::CLI::I18n.new @i18n.stub!(:yardopts).and_return([]) @i18n.stub!(:support_rdoc_document_file!).and_return([]) @i18n.parse_arguments end it "should read .yardopts by default" do @i18n.use_yardopts_file.should == true end it "should use {lib,app}/**/*.rb and ext/**/*.c as default file glob" do @i18n.files.should == ['{lib,app}/**/*.rb', 'ext/**/*.c'] end it "should only show public visibility by default" do @i18n.visibilities.should == [:public] end end describe 'General options' do def self.should_accept(*args, &block) @counter ||= 0 @counter += 1 counter = @counter args.each do |arg| define_method("test_options_#{@counter}", &block) it("should accept #{arg}") { send("test_options_#{counter}", arg) } end end should_accept('--yardopts') do |arg| @i18n = YARD::CLI::I18n.new @i18n.use_document_file = false @i18n.should_receive(:yardopts).at_least(1).times.and_return([]) @i18n.parse_arguments(arg) @i18n.use_yardopts_file.should == true @i18n.parse_arguments('--no-yardopts', arg) @i18n.use_yardopts_file.should == true end should_accept('--yardopts with filename') do |arg| @i18n = YARD::CLI::I18n.new File.should_receive(:read_binary).with('.yardopts_i18n').and_return('') @i18n.use_document_file = false @i18n.parse_arguments('--yardopts', '.yardopts_i18n') @i18n.use_yardopts_file.should == true @i18n.options_file.should == '.yardopts_i18n' end should_accept('--no-yardopts') do |arg| @i18n = YARD::CLI::I18n.new @i18n.use_document_file = false @i18n.should_not_receive(:yardopts) @i18n.parse_arguments(arg) @i18n.use_yardopts_file.should == false @i18n.parse_arguments('--yardopts', arg) @i18n.use_yardopts_file.should == false end should_accept('--exclude') do |arg| YARD.should_receive(:parse).with(['a'], ['nota', 'b']) @i18n.run(arg, 'nota', arg, 'b', 'a') end end describe '.yardopts handling' do before do @i18n.use_yardopts_file = true end it "should search for and use yardopts file specified by #options_file" do File.should_receive(:read_binary).with("test").and_return("-o \n\nMYPATH\nFILE1 FILE2") @i18n.use_document_file = false @i18n.options_file = "test" File.should_receive(:open!).with(File.expand_path("MYPATH"), "wb") @i18n.run @i18n.files.should == ["FILE1", "FILE2"] end end describe '#run' do it "should parse_arguments if run() is called" do @i18n.should_receive(:parse_arguments) @i18n.run end it "should parse_arguments if run(arg1, arg2, ...) is called" do @i18n.should_receive(:parse_arguments) @i18n.run('--private', '-p', 'foo') end it "should not parse_arguments if run(nil) is called" do @i18n.should_not_receive(:parse_arguments) @i18n.run(nil) end end end yard-0.8.7.3/spec/cli/graph_spec.rb0000644000004100000410000000102112261240652017011 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::CLI::Graph do it "should serialize output" do Registry.should_receive(:load).at_least(1).times subject.stub(:yardopts) { [] } subject.options.serializer.should_receive(:serialize).once subject.run end it 'should read yardoc file from .yardopts' do subject.stub(:yardopts) { %w(--db /path/to/db) } subject.options.serializer.should_receive(:serialize).once subject.run Registry.yardoc_file.should == '/path/to/db' end end yard-0.8.7.3/spec/cli/markup_types_spec.rb0000644000004100000410000000121412261240652020437 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::CLI::MarkupTypes do it "lists all available markup types" do YARD::CLI::MarkupTypes.run data = log.io.string exts = YARD::Templates::Helpers::MarkupHelper::MARKUP_EXTENSIONS YARD::Templates::Helpers::MarkupHelper::MARKUP_PROVIDERS.each do |name, providers| data.should match(/\b#{name}\b/) # Match all extensions exts[name].each do |ext| data.should include(".#{ext}") end if exts[name] # Match all provider libs providers.each do |provider| data.should match(/\b#{provider[:lib]}\b/) end end end end yard-0.8.7.3/spec/cli/yardoc_spec.rb0000644000004100000410000006764712261240652017223 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::CLI::Yardoc do before do @yardoc = YARD::CLI::Yardoc.new @yardoc.statistics = false @yardoc.use_document_file = false @yardoc.use_yardopts_file = false @yardoc.generate = false Templates::Engine.stub!(:render) Templates::Engine.stub!(:generate) YARD.stub!(:parse) Registry.stub!(:load) Registry.stub!(:save) end describe 'Defaults' do before do @yardoc = CLI::Yardoc.new @yardoc.stub!(:yardopts).and_return([]) @yardoc.stub!(:support_rdoc_document_file!).and_return([]) @yardoc.parse_arguments end it "should use cache by default" do @yardoc.use_cache.should == false end it "print statistics by default" do @yardoc.statistics.should == true end it "should generate output by default" do @yardoc.generate.should == true end it "should read .yardopts by default" do @yardoc.use_yardopts_file.should == true end it "should read .document by default" do @yardoc.use_document_file.should == true end it "should use {lib,app}/**/*.rb and ext/**/*.c as default file glob" do @yardoc.files.should == ['{lib,app}/**/*.rb', 'ext/**/*.c'] end it "should use rdoc as default markup type (but falls back on none)" do @yardoc.options.markup.should == :rdoc end it "should use default as default template" do @yardoc.options.template.should == :default end it "should use HTML as default format" do @yardoc.options.format.should == :html end it "should use 'Object' as default return type" do @yardoc.options.default_return.should == 'Object' end it "should not hide void return types by default" do @yardoc.options.hide_void_return.should == false end it "should only show public visibility by default" do @yardoc.visibilities.should == [:public] end it "should not list objects by default" do @yardoc.list.should == false end it "should not embed mixins by default" do @yardoc.options.embed_mixins.should be_empty end it "should not set any locale by default" do @yardoc.options.locale.should be_nil end end describe 'General options' do def self.should_accept(*args, &block) @counter ||= 0 @counter += 1 counter = @counter args.each do |arg| define_method("test_options_#{@counter}", &block) it("should accept #{arg}") { send("test_options_#{counter}", arg) } end end should_accept('--single-db') do |arg| @yardoc.parse_arguments(arg) Registry.single_object_db.should == true Registry.single_object_db = nil end should_accept('--no-single-db') do |arg| @yardoc.parse_arguments(arg) Registry.single_object_db.should == false Registry.single_object_db = nil end should_accept('-c', '--use-cache') do |arg| @yardoc.parse_arguments(arg) @yardoc.use_cache.should == true end should_accept('--no-cache') do |arg| @yardoc.parse_arguments(arg) @yardoc.use_cache.should == false end should_accept('--yardopts') do |arg| @yardoc = CLI::Yardoc.new @yardoc.use_document_file = false @yardoc.should_receive(:yardopts).at_least(1).times.and_return([]) @yardoc.parse_arguments(arg) @yardoc.use_yardopts_file.should == true @yardoc.parse_arguments('--no-yardopts', arg) @yardoc.use_yardopts_file.should == true end should_accept('--yardopts with filename') do |arg| @yardoc = CLI::Yardoc.new File.should_receive(:read_binary).with('.foobar').and_return('') @yardoc.use_document_file = false @yardoc.parse_arguments('--yardopts', '.foobar') @yardoc.use_yardopts_file.should == true @yardoc.options_file.should == '.foobar' end should_accept('--no-yardopts') do |arg| @yardoc = CLI::Yardoc.new @yardoc.use_document_file = false @yardoc.should_not_receive(:yardopts) @yardoc.parse_arguments(arg) @yardoc.use_yardopts_file.should == false @yardoc.parse_arguments('--yardopts', arg) @yardoc.use_yardopts_file.should == false end should_accept('--document') do |arg| @yardoc = CLI::Yardoc.new @yardoc.use_yardopts_file = false @yardoc.should_receive(:support_rdoc_document_file!).and_return([]) @yardoc.parse_arguments('--no-document', arg) @yardoc.use_document_file.should == true end should_accept('--no-document') do |arg| @yardoc = CLI::Yardoc.new @yardoc.use_yardopts_file = false @yardoc.should_not_receive(:support_rdoc_document_file!) @yardoc.parse_arguments('--document', arg) @yardoc.use_document_file.should == false end should_accept('-b', '--db') do |arg| @yardoc.parse_arguments(arg, 'test') Registry.yardoc_file.should == 'test' Registry.yardoc_file = '.yardoc' end should_accept('-n', '--no-output') do |arg| Templates::Engine.should_not_receive(:generate) @yardoc.run(arg) end should_accept('--exclude') do |arg| YARD.should_receive(:parse).with(['a'], ['nota', 'b']) @yardoc.run(arg, 'nota', arg, 'b', 'a') end should_accept('--no-save') do |arg| YARD.should_receive(:parse) Registry.should_not_receive(:save) @yardoc.run(arg) end end describe 'Output options' do it "should accept --title" do @yardoc.parse_arguments('--title', 'hello world') @yardoc.options.title.should == 'hello world' end it "should allow --title to have multiple spaces in .yardopts" do File.should_receive(:read_binary).with("test").and_return("--title \"Foo Bar\"") @yardoc.options_file = "test" @yardoc.use_yardopts_file = true @yardoc.run @yardoc.options.title.should == "Foo Bar" end it "should alias --main to the --readme flag" do readme = File.join(File.dirname(__FILE__),'..','..','README.md') @yardoc.parse_arguments('--main', readme) @yardoc.options.readme.should == CodeObjects::ExtraFileObject.new(readme, '') end it "should select a markup provider when --markup-provider or -mp is set" do @yardoc.parse_arguments("-M", "test") @yardoc.options.markup_provider.should == :test @yardoc.parse_arguments("--markup-provider", "test2") @yardoc.options.markup_provider.should == :test2 end it "should select a markup format when -m is set" do @yardoc.should_receive(:verify_markup_options).and_return(true) @yardoc.generate = true @yardoc.parse_arguments('-m', 'markdown') @yardoc.options.markup.should == :markdown end it "should accept --default-return" do @yardoc.parse_arguments *%w( --default-return XYZ ) @yardoc.options.default_return.should == "XYZ" end it "should allow --hide-void-return to be set" do @yardoc.parse_arguments *%w( --hide-void-return ) @yardoc.options.hide_void_return.should be_true end it "should accept --embed-mixins" do @yardoc.parse_arguments *%w( --embed-mixins ) @yardoc.options.embed_mixins.should == ['*'] end it "should accept --embed-mixin MODULE" do @yardoc.parse_arguments *%w( --embed-mixin MyModule ) @yardoc.options.embed_mixins.should == ['MyModule'] end it "should generate all objects with --use-cache" do YARD.should_receive(:parse) Registry.should_receive(:load) Registry.should_receive(:load_all) @yardoc.stub!(:generate).and_return(true) @yardoc.run *%w( --use-cache ) end it "should not print statistics with --no-stats" do @yardoc.stub!(:statistics).and_return(false) CLI::Stats.should_not_receive(:new) @yardoc.run *%w( --no-stats ) end describe '--asset' do before do @yardoc.generate = true @yardoc.stub!(:run_generate) end it "should copy assets to output directory" do FileUtils.should_receive(:cp_r).with('a', 'doc/a') @yardoc.run *%w( --asset a ) @yardoc.assets.should == {'a' => 'a'} end it "should allow multiple --asset options" do FileUtils.should_receive(:cp_r).with('a', 'doc/a') FileUtils.should_receive(:cp_r).with('b', 'doc/b') @yardoc.run *%w( --asset a --asset b ) @yardoc.assets.should == {'a' => 'a', 'b' => 'b'} end it "should not allow from or to to refer to a path above current path" do log.should_receive(:warn).exactly(4).times.with(/invalid/i) @yardoc.run *%w( --asset ../../../etc/passwd ) @yardoc.assets.should be_empty @yardoc.run *%w( --asset a/b/c/d/../../../../../../etc/passwd ) @yardoc.assets.should be_empty @yardoc.run *%w( --asset /etc/passwd ) @yardoc.assets.should be_empty @yardoc.run *%w( --asset normal:/etc/passwd ) @yardoc.assets.should be_empty end it "should allow from:to syntax" do FileUtils.should_receive(:cp_r).with('foo', 'doc/bar') @yardoc.run *%w( --asset foo:bar ) @yardoc.assets.should == {'foo' => 'bar'} end it "should not put from inside of to/ if from is a directory" do begin from = 'tmp_foo' to = 'tmp_bar' full_to = File.join(File.dirname(__FILE__), to) FileUtils.mkdir_p(from) @yardoc.options.serializer.basepath = File.dirname(__FILE__) @yardoc.run("--asset", "#{from}:#{to}") @yardoc.run("--asset", "#{from}:#{to}") File.directory?(full_to).should be_true File.directory?(File.join(full_to, 'tmp_foo')).should be_false ensure FileUtils.rm_rf(from) FileUtils.rm_rf(full_to) end end end describe '--locale' do it 'should apply specified locale to all extra file objects' do File.stub!(:read).with('extra_file1').and_return('') File.stub!(:read).with('extra_file2').and_return('') extra_file_object1 = CodeObjects::ExtraFileObject.new('extra_file1') extra_file_object2 = CodeObjects::ExtraFileObject.new('extra_file2') extra_file_object1.should_receive(:locale=).with('fr') extra_file_object2.should_receive(:locale=).with('fr') CodeObjects::ExtraFileObject.stub!(:new).with('extra_file1').and_return(extra_file_object1) CodeObjects::ExtraFileObject.stub!(:new).with('extra_file2').and_return(extra_file_object2) Dir.stub!(:glob).with('README*').and_return([]) File.stub!(:file?).with('extra_file1').and_return(true) File.stub!(:file?).with('extra_file2').and_return(true) @yardoc.run('--locale=fr', '-', 'extra_file1', 'extra_file2') end end describe '--po-dir' do it 'should set Registry.po_dir' do Registry.should_receive(:po_dir=).with("locale") @yardoc.run('--po-dir=locale') end end end describe '--[no-]api' do before { Registry.clear } it "should allow --api name" do YARD.parse_string <<-eof # @api private class Foo; end # @api public class Bar; end class Baz; end eof @yardoc.run('--api', 'private') @yardoc.options.verifier.run(Registry.all).should == [P('Foo')] end it "should allow multiple --api's to all be shown" do YARD.parse_string <<-eof # @api private class Foo; end # @api public class Bar; end class Baz; end eof @yardoc.run('--api', 'private', '--api', 'public') @yardoc.options.verifier.run(Registry.all). sort_by {|o| o.path }.should == [P('Bar'), P('Foo')] end it "should allow --no-api to specify objects with no @api tag" do YARD.parse_string <<-eof # @api private class Foo; end # @api public class Bar; end class Baz; end eof @yardoc.run('--api', '') @yardoc.options.verifier.run(Registry.all).should == [P('Baz')] @yardoc.options.verifier = Verifier.new @yardoc.run('--no-api') @yardoc.options.verifier.run(Registry.all).should == [P('Baz')] end it "should allow --no-api to work with other --api switches" do YARD.parse_string <<-eof # @api private class Foo; end # @api public class Bar; end class Baz; end eof @yardoc.run('--no-api', '--api', 'public') @yardoc.options.verifier.run(Registry.all). sort_by {|o| o.path }.should == [P('Bar'), P('Baz')] end it "should ensure Ruby code cannot be used" do [':symbol', '42', '"; exit'].each do |ruby| @yardoc.options.verifier.expressions = [] @yardoc.run('--api', ruby) @yardoc.options.verifier.expressions[1].should include(ruby.inspect) end end end describe '--hide-api option' do it "should allow --hide-api to hide objects with api tags" do YARD.parse_string <<-eof # @api private class Foo; end class Bar; end class Baz; end eof @yardoc.run('--hide-api', 'private') @yardoc.options.verifier.run(Registry.all). sort_by {|o| o.path }.should == [P('Bar'), P('Baz')] end it "should allow --hide-api to work with --api" do YARD.parse_string <<-eof # @api private class Foo; end # @api public class Bar; end class Baz; end eof @yardoc.run('--api', 'public', '--hide-api', 'private') @yardoc.options.verifier.run(Registry.all). sort_by {|o| o.path }.should == [P('Bar')] end end describe '--no-private option' do it "should accept --no-private" do obj = mock(:object) obj.should_receive(:tag).ordered.with(:private).and_return(true) @yardoc.parse_arguments *%w( --no-private ) @yardoc.options.verifier.call(obj).should == false end it "should hide object if namespace is @private with --no-private" do ns = mock(:namespace) ns.stub!(:type).and_return(:module) ns.should_receive(:tag).with(:private).and_return(true) obj = mock(:object) obj.stub!(:namespace).and_return(ns) obj.should_receive(:tag).with(:private).and_return(false) @yardoc.parse_arguments *%w( --no-private ) @yardoc.options.verifier.call(obj).should == false end it "should not call #tag on namespace if namespace is proxy with --no-private" do ns = mock(:namespace) ns.should_receive(:is_a?).with(CodeObjects::Proxy).and_return(true) ns.should_not_receive(:tag) obj = mock(:object) obj.stub!(:type).and_return(:class) obj.stub!(:namespace).and_return(ns) obj.stub!(:visibility).and_return(:public) obj.should_receive(:tag).ordered.with(:private).and_return(false) @yardoc.parse_arguments *%w( --no-private ) @yardoc.options.verifier.call(obj).should == true end # @bug gh-197 it "should not call #tag on namespace if namespace is proxy with --no-private" do Registry.clear YARD.parse_string "module Qux; class Foo::Bar; end; end" foobar = Registry.at('Foo::Bar') foobar.namespace.type = :module @yardoc.parse_arguments *%w( --no-private ) @yardoc.options.verifier.call(foobar).should == true end it "should not call #tag on proxy object" do # @bug gh-197 @yardoc.parse_arguments *%w( --no-private ) @yardoc.options.verifier.call(P('ProxyClass')).should == true end it "should hide methods inside a 'private' class/module with --no-private" do Registry.clear YARD.parse_string <<-eof # @private class ABC def foo; end end eof @yardoc.parse_arguments *%w( --no-private ) @yardoc.options.verifier.call(Registry.at('ABC')).should be_false @yardoc.options.verifier.call(Registry.at('ABC#foo')).should be_false end end describe '.yardopts and .document handling' do before do @yardoc.use_yardopts_file = true end it "should search for and use yardopts file specified by #options_file" do File.should_receive(:read_binary).with("test").and_return("-o \n\nMYPATH\nFILE1 FILE2") @yardoc.use_document_file = false @yardoc.options_file = "test" @yardoc.run @yardoc.options.serializer.options[:basepath].should == "MYPATH" @yardoc.files.should == ["FILE1", "FILE2"] end it "should use String#shell_split to split .yardopts tokens" do optsdata = "foo bar" optsdata.should_receive(:shell_split) File.should_receive(:read_binary).with("test").and_return(optsdata) @yardoc.options_file = "test" @yardoc.run end it "should allow opts specified in command line to override yardopts file" do File.should_receive(:read_binary).with(".yardopts").and_return("-o NOTMYPATH") @yardoc.run("-o", "MYPATH", "FILE") @yardoc.options.serializer.options[:basepath].should == "MYPATH" @yardoc.files.should == ["FILE"] end it "should load the RDoc .document file if found" do File.should_receive(:read_binary).with(".yardopts").and_return("-o NOTMYPATH") @yardoc.use_document_file = true @yardoc.stub!(:support_rdoc_document_file!).and_return(["FILE2", "FILE3"]) @yardoc.run("-o", "MYPATH", "FILE1") @yardoc.options.serializer.options[:basepath].should == "MYPATH" @yardoc.files.should == ["FILE2", "FILE3", "FILE1"] end end describe 'Query options' do after { Registry.clear } it "should hide private constants in with default visibilities" do classobj = CodeObjects::ClassObject.new(:root, :Foo) {|o| o.visibility = :private } @yardoc.run @yardoc.options.verifier.run([classobj]).should == [] end it "should setup visibility rules as verifier" do methobj = CodeObjects::MethodObject.new(:root, :test) {|o| o.visibility = :private } File.should_receive(:read_binary).with("test").and_return("--private") @yardoc.use_yardopts_file = true @yardoc.options_file = "test" @yardoc.run @yardoc.options.verifier.call(methobj).should be_true end it "should accept a --query" do @yardoc.parse_arguments *%w( --query @return ) @yardoc.options.verifier.should be_a(Verifier) end it "should accept multiple --query arguments" do obj = mock(:object) obj.should_receive(:tag).ordered.with('return').and_return(true) obj.should_receive(:tag).ordered.with('tag').and_return(false) @yardoc.parse_arguments *%w( --query @return --query @tag ) @yardoc.options.verifier.should be_a(Verifier) @yardoc.options.verifier.call(obj).should == false end end describe 'Extra file arguments' do it "should accept extra files if specified after '-' with source files" do Dir.should_receive(:glob).with('README*').and_return([]) File.should_receive(:file?).with('extra_file1').and_return(true) File.should_receive(:file?).with('extra_file2').and_return(true) File.should_receive(:read).with('extra_file1').and_return('') File.should_receive(:read).with('extra_file2').and_return('') @yardoc.parse_arguments *%w( file1 file2 - extra_file1 extra_file2 ) @yardoc.files.should == %w( file1 file2 ) @yardoc.options.files.should == [CodeObjects::ExtraFileObject.new('extra_file1', ''), CodeObjects::ExtraFileObject.new('extra_file2', '')] end it "should accept files section only containing extra files" do Dir.should_receive(:glob).with('README*').and_return([]) @yardoc.parse_arguments *%w( - LICENSE ) @yardoc.files.should == %w( {lib,app}/**/*.rb ext/**/*.c ) @yardoc.options.files.should == [CodeObjects::ExtraFileObject.new('LICENSE', '')] end it "should accept globs as extra files" do Dir.should_receive(:glob).with('README*').and_return [] Dir.should_receive(:glob).with('*.txt').and_return ['a.txt', 'b.txt'] File.should_receive(:read).with('a.txt').and_return('') File.should_receive(:read).with('b.txt').and_return('') File.should_receive(:file?).with('a.txt').and_return(true) File.should_receive(:file?).with('b.txt').and_return(true) @yardoc.parse_arguments *%w( file1 file2 - *.txt ) @yardoc.files.should == %w( file1 file2 ) @yardoc.options.files.should == [CodeObjects::ExtraFileObject.new('a.txt', ''), CodeObjects::ExtraFileObject.new('b.txt', '')] end it "should warn if extra file is not found" do log.should_receive(:warn).with(/Could not find extra file: UNKNOWN/) @yardoc.parse_arguments *%w( - UNKNOWN ) end it "should warn if readme file is not found" do log.should_receive(:warn).with(/Could not find readme file: UNKNOWN/) @yardoc.parse_arguments *%w( -r UNKNOWN ) end it "should use first file as readme if no readme is specified when using --one-file" do Dir.should_receive(:glob).with('README*').and_return [] Dir.should_receive(:glob).with('lib/*.rb').and_return(['lib/foo.rb']) File.should_receive(:read).with('lib/foo.rb').and_return('') @yardoc.parse_arguments *%w( --one-file lib/*.rb ) @yardoc.options.readme.should == CodeObjects::ExtraFileObject.new('lib/foo.rb', '') end it "should use readme it exists when using --one-file" do Dir.should_receive(:glob).with('README*').and_return ['README'] File.should_receive(:read).with('README').and_return('') @yardoc.parse_arguments *%w( --one-file lib/*.rb ) @yardoc.options.readme.should == CodeObjects::ExtraFileObject.new('README', '') end it "should not allow US-ASCII charset when using --one-file" do ienc = Encoding.default_internal eenc = Encoding.default_external log.should_receive(:warn).with(/not compatible with US-ASCII.*using ASCII-8BIT/) @yardoc.parse_arguments *%w( --one-file --charset us-ascii ) Encoding.default_internal.name.should == 'ASCII-8BIT' Encoding.default_external.name.should == 'ASCII-8BIT' Encoding.default_internal = ienc Encoding.default_external = eenc end if defined?(::Encoding) end describe 'Source file arguments' do it "should accept no params and parse {lib,app}/**/*.rb ext/**/*.c" do @yardoc.parse_arguments @yardoc.files.should == %w( {lib,app}/**/*.rb ext/**/*.c ) end end describe 'Tags options' do def tag_created(switch, factory_method) visible_tags = mock(:visible_tags) visible_tags.should_receive(:|).ordered.with([:foo]) visible_tags.should_receive(:-).ordered.with([]).and_return(visible_tags) Tags::Library.should_receive(:define_tag).with('Foo', :foo, factory_method) Tags::Library.stub!(:visible_tags=) Tags::Library.should_receive(:visible_tags).at_least(1).times.and_return(visible_tags) @yardoc.parse_arguments("--#{switch}-tag", 'foo') end def tag_hidden(tag) visible_tags = mock(:visible_tags) visible_tags.should_receive(:|).ordered.with([tag]) visible_tags.should_receive(:-).ordered.with([tag]).and_return([]) Tags::Library.should_receive(:define_tag).with(tag.to_s.capitalize, tag, nil) Tags::Library.stub!(:visible_tags=) Tags::Library.should_receive(:visible_tags).at_least(1).times.and_return(visible_tags) end it "should accept --tag" do Tags::Library.should_receive(:define_tag).with('Title of Foo', :foo, nil) @yardoc.parse_arguments('--tag', 'foo:Title of Foo') end it "should accept --tag without title (and default to captialized tag name)" do Tags::Library.should_receive(:define_tag).with('Foo', :foo, nil) @yardoc.parse_arguments('--tag', 'foo') end it "should only list tag once if declared twice" do visible_tags = [] Tags::Library.stub!(:define_tag) Tags::Library.stub!(:visible_tags).and_return([:foo]) Tags::Library.stub!(:visible_tags=) {|value| visible_tags = value } @yardoc.parse_arguments('--tag', 'foo', '--tag', 'foo') visible_tags.should == [:foo] end it "should accept --type-tag" do tag_created 'type', :with_types end it "should accept --type-name-tag" do tag_created 'type-name', :with_types_and_name end it "should accept --name-tag" do tag_created 'name', :with_name end it "should accept --title-tag" do tag_created 'title', :with_title_and_text end it "should accept --hide-tag before tag is listed" do tag_hidden(:anewfoo) @yardoc.parse_arguments('--hide-tag', 'anewfoo', '--tag', 'anewfoo') end it "should accept --hide-tag after tag is listed" do tag_hidden(:anewfoo2) @yardoc.parse_arguments('--tag', 'anewfoo2', '--hide-tag', 'anewfoo2') end it "should accept --transitive-tag" do @yardoc.parse_arguments('--transitive-tag', 'foo') Tags::Library.transitive_tags.should include(:foo) end it "should accept --non-transitive-tag" do Tags::Library.transitive_tags |= [:foo] @yardoc.parse_arguments('--non-transitive-tag', 'foo') Tags::Library.transitive_tags.should_not include(:foo) end end describe 'Safe mode' do before do YARD::Config.stub!(:options).and_return(:safe_mode => true) end it "should not allow --load or -e in safe mode" do @yardoc.should_not_receive(:require) @yardoc.run('--load', 'foo') @yardoc.run('-e', 'foo') end it "should not allow --query in safe mode" do @yardoc.run('--query', 'foo') @yardoc.options.verifier.expressions.should_not include("foo") end it "should not allow modifying the template paths" do YARD::Templates::Engine.should_not_receive(:register_template_path) @yardoc.run('-p', 'foo') @yardoc.run('--template-path', 'foo') end end describe 'Markup Loading' do it "should load rdoc markup if no markup is provided" do @yardoc.generate = true @yardoc.run @yardoc.options.markup.should == :rdoc end it "should load rdoc markup even when no output is specified" do @yardoc.parse_arguments('--no-output') @yardoc.options.markup.should == :rdoc end it "should warn if rdoc cannot be loaded and fallback to :none" do mod = YARD::Templates::Helpers::MarkupHelper mod.clear_markup_cache mod.const_get(:MARKUP_PROVIDERS).should_receive(:[]).with(:rdoc).and_return([{:lib => 'INVALID'}]) log.should_receive(:warn).with(/Could not load default RDoc formatter/) @yardoc.stub(:generate) { @yardoc.options.files = []; true } @yardoc.run @yardoc.options.markup.should == :none mod.clear_markup_cache end it "should error immediately if markup for any files are missing" do mod = YARD::Templates::Helpers::MarkupHelper mod.clear_markup_cache mod.const_get(:MARKUP_PROVIDERS).should_receive(:[]).with(:markdown).and_return([{:lib => 'INVALID'}]) log.should_receive(:error).with(/Missing 'INVALID' gem for Markdown formatting/) files = [CodeObjects::ExtraFileObject.new('test.md', '')] @yardoc.stub(:generate) { @yardoc.options.files = files; true } @yardoc.run mod.clear_markup_cache end it "should error immediately if markup for any files are missing (file markup specified in attributes)" do mod = YARD::Templates::Helpers::MarkupHelper mod.clear_markup_cache mod.const_get(:MARKUP_PROVIDERS).should_receive(:[]).with(:markdown).and_return([{:lib => 'INVALID'}]) log.should_receive(:error).with(/Missing 'INVALID' gem for Markdown formatting/) files = [CodeObjects::ExtraFileObject.new('test', '# @markup markdown')] @yardoc.stub(:generate) { @yardoc.options.files = files; true } @yardoc.run mod.clear_markup_cache end end describe '#run' do it "should parse_arguments if run() is called" do @yardoc.should_receive(:parse_arguments) @yardoc.run end it "should parse_arguments if run(arg1, arg2, ...) is called" do @yardoc.should_receive(:parse_arguments) @yardoc.run('--private', '-p', 'foo') end it "should not parse_arguments if run(nil) is called" do @yardoc.should_not_receive(:parse_arguments) @yardoc.run(nil) end end end yard-0.8.7.3/spec/cli/display_spec.rb0000644000004100000410000000175412261240652017372 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::CLI::Display do before do Registry.stub(:load) @object = CodeObjects::ClassObject.new(:root, :Foo) @object.docstring = 'Foo bar' end it "displays an object" do YARD::CLI::Display.run('-f', 'text', 'Foo') log.io.string.strip.should eq(@object.format.strip) end it "wraps output with -l (defaulting to layout)" do YARD::CLI::Display.run('-l', '-f', 'html', 'Foo') formatted_output = @object.format(:format => :html).strip actual_output = log.io.string.strip actual_output.should_not eq(formatted_output) actual_output.should include(formatted_output) end it "wraps output with --layout onefile" do YARD::CLI::Display.run('--layout', 'onefile', '-f', 'html', 'Foo') formatted_output = @object.format(:format => :html).strip actual_output = log.io.string.strip actual_output.should_not eq(formatted_output) actual_output.should include(formatted_output) end end yard-0.8.7.3/spec/cli/list_spec.rb0000644000004100000410000000037412261240652016675 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/../spec_helper' describe YARD::CLI::List do it "should pass command off to Yardoc with --list" do YARD::CLI::Yardoc.should_receive(:run).with('-c', '--list', '--foo') YARD::CLI::List.run('--foo') end end yard-0.8.7.3/spec/cli/command_spec.rb0000644000004100000410000000210212261240652017327 0ustar www-datawww-datarequire File.dirname(__FILE__) + "/../spec_helper" require 'optparse' describe YARD::CLI::Command do describe '#parse_options' do before do @options = OptionParser.new @saw_foo = false @options.on('--foo') { @saw_foo = true } end def parse(*args) CLI::Command.new.send(:parse_options, @options, args) args end it "should skip unrecognized options but continue to next option" do log.should_receive(:warn).with(/Unrecognized.*--list/) log.should_receive(:warn).with(/Unrecognized.*--list2/) parse('--list', '--list2', '--foo') @saw_foo.should be_true end it "should skip unrecognized options and any extra non-option arg that follows" do log.should_receive(:warn).with(/Unrecognized.*--list/) parse('--list', 'foo', '--foo') @saw_foo.should be_true end it "should stop retrying to parse at non-switch argument" do log.should_receive(:warn).with(/Unrecognized.*--list/) args = parse('--list', 'foo', 'foo', 'foo') args.should == %w(foo foo) end end end yard-0.8.7.3/spec/docstring_parser_spec.rb0000644000004100000410000001404112261240652020517 0ustar www-datawww-datarequire File.dirname(__FILE__) + "/spec_helper" describe YARD::DocstringParser do after(:all) do YARD::Registry.clear end def parse(content, object = nil, handler = nil) @library ||= Tags::Library.instance @parser = DocstringParser.new(@library) @parser.parse(content, object, handler) @parser end def docstring(content, object = nil, handler = nil) parse(content, object, handler).to_docstring end describe '#parse' do it "should parse comments into tags" do doc = docstring(<<-eof) @param name Hello world how are you? @param name2 this is a new line @param name3 and this is a new paragraph: right here. eof tags = doc.tags(:param) tags[0].name.should == "name" tags[0].text.should == "Hello world\nhow are you?" tags[1].name.should == "name2" tags[1].text.should == "this is a new line" tags[2].name.should == "name3" tags[2].text.should == "and this\nis a new paragraph:\n\nright here." end it "should end parsing a tag on de-dent" do doc = docstring(<<-eof) @note test one two three rest of docstring eof doc.tag(:note).text.should == "test\none two three" doc.should == "rest of docstring" end it "should parse examples embedded in doc" do doc = docstring(<<-eof) test string here @example code def foo(x, y, z) end class A; end more stuff eof doc.should == "test string here\nmore stuff" doc.tag(:example).text.should == "\ndef foo(x, y, z)\nend\n\nclass A; end" end it "should remove only original indentation from beginning of line in tags" do doc = docstring(<<-eof) @param name some value foo bar baz eof doc.tag(:param).text.should == "some value\nfoo bar\n baz" end it "should allow numbers in tags" do Tags::Library.define_tag(nil, :foo1) Tags::Library.define_tag(nil, :foo2) Tags::Library.define_tag(nil, :foo3) doc = docstring(<<-eof) @foo1 bar1 @foo2 bar2 @foo3 bar3 eof doc.tag(:foo1).text.should == "bar1" doc.tag(:foo2).text.should == "bar2" end it "should end tag on newline if next line is not indented" do doc = docstring(<<-eof) @author bar1 @api bar2 Hello world eof doc.tag(:author).text.should == "bar1" doc.tag(:api).text.should == "bar2" end it "should warn about unknown tag" do log.should_receive(:warn).with(/Unknown tag @hello$/) docstring("@hello world") end it "should not add trailing whitespace to freeform tags" do doc = docstring("@api private \t ") doc.tag(:api).text.should == "private" end end describe '#parse with custom tag library' do class TestLibrary < Tags::Library; end before { @library = TestLibrary.new } it "should accept valid tags" do valid = %w( testing valid is_a is_A __ ) valid.each do |tag| TestLibrary.define_tag("Tag", tag) doc = docstring('@' + tag + ' foo bar') doc.tag(tag).text.should == 'foo bar' end end it "should not parse invalid tag names" do invalid = %w( @ @return@ @param, @x-y @.x.y.z ) invalid.each do |tag| docstring(tag + ' foo bar').should == tag + ' foo bar' end end it "should allow namespaced tags in the form @x.y.z" do TestLibrary.define_tag("Tag", 'x.y.z') doc = docstring("@x.y.z foo bar") doc.tag('x.y.z').text.should == 'foo bar' end it "should ignore new directives without @! prefix syntax" do TestLibrary.define_directive('dir1', Tags::ScopeDirective) log.should_receive(:warn).with(/@dir1/) docstring("@dir1") end %w(attribute endgroup group macro method scope visibility).each do |tag| it "should handle non prefixed @#{tag} syntax as directive, not tag" do TestLibrary.define_directive(tag, Tags::ScopeDirective) parse("@#{tag}") @parser.directives.first.should be_a(Tags::ScopeDirective) end end it "should handle directives with @! prefix syntax" do TestLibrary.define_directive('dir1', Tags::ScopeDirective) docstring("@!dir1 class") @parser.state.scope.should == :class end end describe '#text' do it "should only return text data" do parse("Foo\n@param foo x y z\nBar") @parser.text.should == "Foo\nBar" end end describe '#raw_text' do it "should return the entire original data" do data = "Foo\n@param foo x y z\nBar" parse(data) @parser.raw_text.should == data end end describe '#tags' do it "should return the parsed tags" do data = "Foo\n@param foo x y z\nBar" parse(data) @parser.tags.size.should == 1 @parser.tags.first.tag_name.should == 'param' end end describe '#directives' do it "should group all processed directives" do data = "Foo\n@!scope class\n@!visibility private\nBar" parse(data) dirs = @parser.directives dirs.size == 2 dirs[0].should be_a(Tags::ScopeDirective) dirs[0].tag.text.should == 'class' dirs[1].should be_a(Tags::VisibilityDirective) dirs[1].tag.text.should == 'private' end end describe '#state' do it "should handle modified state" do parse("@!scope class") @parser.state.scope.should == :class end end describe 'after_parse' do it "should allow specifying of callbacks" do parser = DocstringParser.new the_yielded_obj = nil DocstringParser.after_parse {|obj| the_yielded_obj = obj } parser.parse("Some text") the_yielded_obj.should == parser end it "should warn about invalid named parameters" do log.should_receive(:warn).with(/@param tag has unknown parameter name: notaparam/) YARD.parse_string <<-eof # @param notaparam foo def foo(a) end eof end it "should warn about duplicate named parameters" do log.should_receive(:warn).with(/@param tag has duplicate parameter name: a/) YARD.parse_string <<-eof # @param a foo # @param a foo def foo(a) end eof end end end yard-0.8.7.3/lib/0000755000004100000410000000000012261240652013424 5ustar www-datawww-datayard-0.8.7.3/lib/rubygems_plugin.rb0000644000004100000410000000032712261240652017166 0ustar www-datawww-dataunless defined?(Gem::DocManager.load_yardoc) require File.expand_path(File.dirname(__FILE__) + '/yard/rubygems/specification') require File.expand_path(File.dirname(__FILE__) + '/yard/rubygems/doc_manager') end yard-0.8.7.3/lib/yard/0000755000004100000410000000000012261240652014363 5ustar www-datawww-datayard-0.8.7.3/lib/yard/tags/0000755000004100000410000000000012261240652015321 5ustar www-datawww-datayard-0.8.7.3/lib/yard/tags/tag_format_error.rb0000644000004100000410000000012012261240652021173 0ustar www-datawww-datamodule YARD module Tags class TagFormatError < Exception end end endyard-0.8.7.3/lib/yard/tags/default_tag.rb0000644000004100000410000000040312261240652020122 0ustar www-datawww-datamodule YARD module Tags class DefaultTag < Tag attr_reader :defaults def initialize(tag_name, text, types = nil, name = nil, defaults = nil) super(tag_name, text, types, name) @defaults = defaults end end end endyard-0.8.7.3/lib/yard/tags/option_tag.rb0000644000004100000410000000032312261240652020007 0ustar www-datawww-datamodule YARD module Tags class OptionTag < Tag attr_accessor :pair def initialize(tag_name, name, pair) super(tag_name, nil, nil, name) @pair = pair end end end end yard-0.8.7.3/lib/yard/tags/directives.rb0000644000004100000410000005175212261240652020021 0ustar www-datawww-datarequire 'ostruct' module YARD module Tags # The base directive class. Subclass this class to create a custom # directive, registering it with {Library.define_directive}. Directive # classes are executed via the {#call} method, which perform all directive # processing on the object. # # If processing occurs within a handler, the {#handler} attribute is # available to access more information about parsing context and state. # Handlers are only available when parsing from {Parser::SourceParser}, # not when parsing directly from {DocstringParser}. If the docstring is # attached to an object declaration, {#object} will be set and available # to modify the generated code object directly. Note that both of these # attributes may be nil, and directives should test their existence # before attempting to use them. # # @abstract Subclasses should implement {#call}. # @see Library.define_directive # @since 0.8.0 class Directive # @return [Tag] the meta-data tag containing data input to the directive attr_accessor :tag # Set this field to replace the directive definition inside of a docstring # with arbitrary text. For instance, the {MacroDirective} uses this field # to expand its macro data in place of the call to a +@!macro+. # # @return [String] the text to expand in the original docstring in place # of this directive definition. # @return [nil] if no expansion should take place for this directive attr_accessor :expanded_text # @return [DocstringParser] the parser that is parsing all tag # information out of the docstring attr_accessor :parser # @!attribute [r] object # @return [CodeObjects::Base, nil] the object the parent docstring is # attached to. May be nil. def object; parser.object end # @!attribute [r] handler # @return [Handlers::Base, nil] the handler object the docstring parser # might be attached to. May be nil. Only available when parsing # through {Parser::SourceParser}. def handler; parser.handler end # @!endgroup # @param [Tag] tag the meta-data tag containing all input to the docstring # @param [DocstringParser] parser the docstring parser object def initialize(tag, parser) self.tag = tag self.parser = parser self.expanded_text = nil end # @!group Parser callbacks # Called when processing the directive. Subclasses should implement # this method to perform all functionality of the directive. # # @abstract implement this method to perform all data processing for # the directive. # @return [void] def call; raise NotImplementedError end # Called after parsing all directives and tags in the docstring. Used # to perform any cleanup after all directives perform their main task. # @return [void] def after_parse; end protected :parser end # Ends a group listing definition. Group definition automatically end # when class or module blocks are closed, and defining a new group overrides # the last group definition, but occasionally you need to end the current # group to return to the default listing. Use {tag:!group} to begin a # group listing. # # @example # class Controller # # @!group Callbacks # # def before_filter; end # def after_filter; end # # # @!endgroup # # def index; end # end # @see tag:!group # @since 0.6.0 class EndGroupDirective < Directive def call return unless handler handler.extra_state.group = nil end end # Defines a group listing. All methods (and attributes) seen after this # directive are placed into a group with the given description as the # group name. The group listing is used by templates to organize methods # and attributes into respective logical groups. To end a group listing # use {tag:!endgroup}. # # @note A group definition only applies to the scope it is defined in. # If a new class or module is opened after the directive, this directive # will not apply to methods in that class or module. # @example # # @!group Callbacks # # def before_filter; end # def after_filter; end # @see tag:!endgroup # @since 0.6.0 class GroupDirective < Directive def call return unless handler handler.extra_state.group = tag.text end end # Defines a block of text to be expanded whenever the macro is called by name # in subsequent docstrings. The macro data can be any arbitrary text data, be # it regular documentation, meta-data tags or directives. # # == Defining a Macro # # A macro must first be defined in order to be used. Note that a macro is also # expanded upon definition if it defined on an object (the docstring of a # method, class, module or constant object as opposed to a free standing # comment). To define a macro, use the "new" or "attach" identifier in the # types specifier list. A macro will also automatically be created if an # indented macro data block is given, so the keywords are not strictly needed. # # === Anonymous Macros # # In addition to standard named macros, macros can be defined anonymously if # no name is given. In this case, they can not be re-used in future docstrings, # but they will expand in the first definition. This is useful when needing # to take advantage of the macro expansion variables (described below). # # == Using a Macro # # To re-use a macro in another docstring after it is defined, simply use # @!macro the_name with no indented block of macro data. The resulting # data will be expanded in place. # # == Attaching a Macro to a DSL Method # # Macros can be defined to auto-expand on DSL-style class method calls. To # define a macro to be auto expanded in this way, use the "attach" keyword # in the type specifier list ("new" is implied). # # Attached macros can also be attached directly on the class method declaration # that provides the DSL method to its subclasses. The syntax in either case # is the same. # # == Macro Expansion Variables # # In the case of using macros on DSL-style method calls, a number of expansion # variables can be used for interpolation inside of the macro data. The variables, # similar in syntax to Ruby's global variables, are as follows: # # * $0 - the method name being called # * $1, $2, $3, ... - the Nth argument in the method call # * $& - the full source line # # The following example shows what the expansion variables might hold for a given # DSL method call: # # property :foo, :a, :b, :c, String # # $0 => "property" # # $1 => "foo" # # $2 => "a" # # $& => "property :foo, :a, :b, :c, String" # # === Ranges # # Ranges are also acceptable with the syntax ${N-M}. Negative values # on either N or M are valid, and refer to indexes from the end of the list. # Consider a DSL method that creates a method using the first argument with # argument names following, ending with the return type of the method. This # could be documented as: # # # @!macro dsl_method # # @!method $1(${2--2}) # # @return [${-1}] the return value of $0 # create_method_with_args :foo, :a, :b, :c, String # # As described, the method is using the signature foo(a, b, c) and the return # type from the last argument, +String+. When using ranges, tokens are joined # with commas. Note that this includes using $0: # # !!!plain # $0-1 # => Interpolates to "create_method_with_args, foo" # # If you want to separate them with spaces, use $1 $2 $3 $4 .... Note that # if the token cannot be expanded, it will return the empty string (not an error), # so it would be safe to list $1 $2 ... $10, for example. # # === Escaping Interpolation # # Interpolation can be escaped by prefixing the +$+ with +\\\+, like so: # # # @!macro foo # # I have \$2.00 USD. # # @example Defining a simple macro # # @!macro [new] returnself # # @return [self] returns itself # @example Using a simple macro in multiple docstrings # # Documentation for map # # ... # # @macro returnself # def map; end # # # Documentation for filter # # ... # # @macro returnself # def filter; end # @example Attaching a macro to a class method (for DSL usage) # class Resource # # Defines a new property # # @param [String] name the property name # # @param [Class] type the property's type # # @!macro [attach] property # # @return [$2] the $1 property # def self.property(name, type) end # end # # class Post < Resource # property :title, String # property :view_count, Integer # end # @example Attaching a macro directly to a DSL method # class Post < Resource # # @!macro [attach] property # # @return [$2] the $1 property # property :title, String # # # Macro will expand on this definition too # property :view_count, Integer # end # @since 0.7.0 class MacroDirective < Directive def call raise TagFormatError if tag.name.nil? && tag.text.to_s.empty? unless macro_data = find_or_create warn return end self.expanded_text = expand(macro_data) end private def new? (tag.types && tag.types.include?('new')) || (tag.text && !tag.text.strip.empty?) end def attach? new? && # must have data or there is nothing to attach class_method? || # always attach to class methods (tag.types && tag.types.include?('attach')) end def class_method? object && object.is_a?(CodeObjects::MethodObject) && object.scope == :class end def anonymous? tag.name.nil? || tag.name.empty? end def expand(macro_data) return if attach? && class_method? return if !anonymous? && new? && (!handler || handler.statement.source.empty?) call_params = [] caller_method = nil full_source = '' if handler call_params = handler.call_params caller_method = handler.caller_method full_source = handler.statement.source end all_params = ([caller_method] + call_params).compact CodeObjects::MacroObject.expand(macro_data, all_params, full_source) end def find_or_create if new? || attach? if handler && attach? obj = object ? object : P("#{handler.namespace}.#{handler.caller_method}") else obj = nil end if anonymous? # anonymous macro return tag.text || "" else macro = CodeObjects::MacroObject.create(tag.name, tag.text, obj) end else macro = CodeObjects::MacroObject.find(tag.name) end macro ? macro.macro_data : nil end def warn if object && handler log.warn "Invalid/missing macro name for " + "#{object.path} (#{handler.parser.file}:#{handler.statement.line})" end end end # Defines a method object with a given method signature, using indented # block data as the method's docstring. The signature is similar to the # {tag:overload} tag. The comment containing this directive does not need # to be attached to any source, but if it is, that source code will be # used as the method's source. # # To define an attribute method, see {tag:!attribute} # # @note For backwards compatibility support, you do not need to indent # the method's docstring text. If a +@!method+ directive is seen with # no indented block, the entire docstring is used as the new method's # docstring text. # @example Defining a simple method # # @!method quit(username, message = "Quit") # # Sends a quit message to the server for a +username+. # # @param [String] username the username to quit # # @param [String] message the quit message # quit_message_method # @example Attaching multiple methods to the same source # # @!method method1 # # @!method method2 # create_methods :method1, :method2 # @see tag:!attribute # @since 0.7.0 class MethodDirective < Directive SCOPE_MATCH = /\A\s*self\s*\.\s*/ def call; end def after_parse return unless handler use_indented_text create_object end protected def method_name sig = sanitized_tag_signature if sig && sig =~ /^#{CodeObjects::METHODNAMEMATCH}(\s|\(|$)/ sig[/\A\s*([^\(; \t]+)/, 1] else handler.call_params.first end end def method_signature "def #{sanitized_tag_signature || method_name}" end def sanitized_tag_signature if tag.name && tag.name =~ SCOPE_MATCH parser.state.scope = :class $' else tag.name end end def use_indented_text return if tag.text.empty? handler = parser.handler object = parser.object self.parser = parser.class.new(parser.library) parser.state.inside_directive = true parser.parse(tag.text, object, handler) parser.state.inside_directive = false end def create_object name = method_name scope = parser.state.scope || handler.scope visibility = parser.state.visibility || handler.visibility ns = CodeObjects::NamespaceObject === object ? object : handler.namespace obj = CodeObjects::MethodObject.new(ns, name, scope) handler.register_file_info(obj) handler.register_source(obj) handler.register_visibility(obj, visibility) handler.register_group(obj) obj.signature = method_signature obj.parameters = OverloadTag.new(:overload, method_signature).parameters obj.docstring = Docstring.new!(parser.text, parser.tags, obj, parser.raw_text, parser.reference) handler.register_module_function(obj) obj end end # Defines an attribute with a given name, using indented block data as the # attribute's docstring. If the type specifier is supplied with "r", "w", or # "rw", the attribute is made readonly, writeonly or readwrite respectively. # A readwrite attribute is the default, if no type is specified. The comment # containing this directive does not need to be attached to any source, but # if it is, that source code will be used as the method's source. # # To define an regular method, see {tag:!method} # # @note For backwards compatibility support, you do not need to indent # the attribute's docstring text. If an +@!attribute+ directive is seen with # no indented block, the entire docstring is used as the new attribute's # docstring text. # @example Defining a simple readonly attribute # # @!attribute [r] count # # @return [Fixnum] the size of the list # @example Defining a simple readwrite attribute # # @!attribute name # # @return [String] the name of the user # @see tag:!method # @since 0.7.0 class AttributeDirective < MethodDirective def after_parse return unless handler use_indented_text create_attribute_data(create_object) end protected def method_name name = sanitized_tag_signature || handler.call_params.first name += '=' unless readable? name end def method_signature if readable? "def #{method_name}" else "def #{method_name}(value)" end end private def create_attribute_data(object) return unless object clean_name = object.name.to_s.sub(/=$/, '') attrs = object.namespace.attributes[object.scope] attrs[clean_name] ||= SymbolHash[:read => nil, :write => nil] if readable? attrs[clean_name][:read] = object end if writable? if object.name.to_s[-1,1] == '=' writer = object writer.parameters = [['value', nil]] else writer = CodeObjects::MethodObject.new(object.namespace, object.name.to_s + '=', object.scope) writer.signature = "def #{object.name}=(value)" writer.visibility = object.visibility writer.dynamic = object.dynamic writer.source = object.source writer.group = object.group writer.parameters = [['value', nil]] handler.register_file_info(writer) end attrs[clean_name][:write] = writer end end def writable? !tag.types || tag.types.join.include?('w') end def readable? !tag.types || tag.types.join =~ /(?!w)r/ end end # Parses a block of code as if it were present in the source file at that # location. This directive is useful if a class has dynamic meta-programmed # behaviour that cannot be recognized by YARD. # # You can specify the language of the code block using the types # specification list. By default, the code language is "ruby". # # @example Documenting dynamic module inclusion # class User # # includes "UserMixin" and extends "UserMixin::ClassMethods" # # using the UserMixin.included callback. # # @!parse include UserMixin # # @!parse extend UserMixin::ClassMethods # end # @example Declaring a method as an attribute # # This should really be an attribute # # @!parse attr_reader :foo # def object; @parent.object end # @example Parsing C code # # @!parse [c] # # void Init_Foo() { # # rb_define_method(rb_cFoo, "method", method, 0); # # } # @since 0.8.0 class ParseDirective < Directive def call lang = tag.types ? tag.types.first.to_sym : (handler ? handler.parser.parser_type : :ruby) if handler && lang == handler.parser.parser_type pclass = Parser::SourceParser.parser_types[handler.parser.parser_type] pobj = pclass.new(tag.text, handler.parser.file) pobj.parse handler.parser.process(pobj.enumerator) else # initialize a new parse chain src_parser = Parser::SourceParser.new(lang, handler ? handler.globals : nil) src_parser.file = handler.parser.file if handler src_parser.parse(StringIO.new(tag.text)) end end end # Modifies the current parsing scope (class or instance). If this # directive is defined on a docstring attached to an object definition, # it is applied only to that object. Otherwise, it applies the scope # to all future objects in the namespace. # # @example Modifying the scope of a DSL method # # @!scope class # cattr_accessor :subclasses # @example Modifying the scope of a set of methods # # @!scope class # # # Documentation for method1 # def method1; end # # # Documentation for method2 # def method2; end # @since 0.7.0 class ScopeDirective < Directive def call if %w(class instance module).include?(tag.text) if object.is_a?(CodeObjects::MethodObject) object.scope = tag.text.to_sym else parser.state.scope = tag.text.to_sym end end end end # Modifies the current parsing visibility (public, protected, or private). # If this directive is defined on a docstring attached to an object # definition, it is applied only to that object. Otherwise, it applies # the visibility to all future objects in the namespace. # # @example Modifying the visibility of a DSL method # # @!visibility private # cattr_accessor :subclasses # @example Modifying the visibility of a set of methods # # Note that Ruby's "protected" is recommended over this directive # # @!visibility protected # # # Documentation for method1 # def method1; end # # # Documentation for method2 # def method2; end # @since 0.7.0 class VisibilityDirective < Directive def call if %w(public protected private).include?(tag.text) if object.is_a?(CodeObjects::Base) object.visibility = tag.text.to_sym elsif handler && !parser.state.inside_directive handler.visibility = tag.text.to_sym else parser.state.visibility = tag.text.to_sym end end end end end endyard-0.8.7.3/lib/yard/tags/tag.rb0000644000004100000410000000421312261240652016421 0ustar www-datawww-datamodule YARD module Tags # Represents a metadata tag value (+@tag+). Tags can have any combination of # {#types}, {#name} and {#text}, or none of the above. # # @example Programmatic tag creation # # The following docstring syntax: # # @param [String, nil] arg an argument # # # # is equivalent to: # Tag.new(:param, 'an argument', ['String', 'nil'], 'arg') class Tag # @return [String] the name of the tag attr_accessor :tag_name # @return [String] the tag text associated with the tag # @return [nil] if no tag text is supplied attr_accessor :text # @return [Array] a list of types associated with the tag # @return [nil] if no types are associated with the tag attr_accessor :types # @return [String] a name associated with the tag attr_accessor :name # @return [CodeObjects::Base] the associated object attr_accessor :object # Creates a new tag object with a tag name and text. Optionally, formally declared types # and a key name can be specified. # # Types are mainly for meta tags that rely on type information, such as +param+, +return+, etc. # # Key names are for tags that declare meta data for a specific key or name, such as +param+, # +raise+, etc. # # @param [#to_s] tag_name the tag name to create the tag for # @param [String] text the descriptive text for this tag # @param [Array] types optional type list of formally declared types # for the tag # @param [String] name optional key name which the tag refers to def initialize(tag_name, text, types = nil, name = nil) @tag_name, @text, @name, @types = tag_name.to_s, text, name, (types ? [types].flatten.compact : nil) end # Convenience method to access the first type specified. This should mainly # be used for tags that only specify one type. # # @return [String] the first of the list of specified types # @see #types def type types.first end end end endyard-0.8.7.3/lib/yard/tags/ref_tag.rb0000644000004100000410000000013112261240652017250 0ustar www-datawww-datamodule YARD module Tags module RefTag attr_accessor :owner end end end yard-0.8.7.3/lib/yard/tags/library.rb0000644000004100000410000006160112261240652017316 0ustar www-datawww-datamodule YARD module Tags # Keeps track of all the registered meta-data tags and directives. # Also allows for defining of custom tags and customizing the tag parsing # syntax. # # == Defining Custom Meta-Data Tags # # To define a custom tag, use {define_tag}. You should pass the tag # name and the factory method to use when creating the tag. If you do not # provide a factory method to use, it will default to {DefaultFactory#parse_tag} # # You can also define tag objects manually by simply implementing a "tagname_tag" # method that returns a {Tag} object, but they will not take advantage of tag factory # parsing: # # def mytag_tag(text) # Tag.new(:mytag, text) # end # # == Defining Custom Directives # # Directives can be defined by calling the {define_directive} method, taking # the directive name, an optional tag factory parser method (to parse the # data in the directive into a temporary {Tag} object) and a {Directive} subclass # that performs the directive processing. For more information on creating a # Directive subclass, see the {Directive} class documentation. # # Similar to tags, Directives can also be defined manually, in this case using # the method name "mydirective_directive" and returning a new {Directive} object: # # def mydirective_directive(tag, parser) # MyDirective.new(tag, parser) # end # # == Namespaced Tags # # In YARD 0.8.0+, tags can be namespaced using the '.' character. It is recommended # to namespace project specific tags, like +@yard.tag_name+, so that tags do not # collide with other plugins or new built-in tags. # # == Adding/Changing the Tag Syntax # # If you have specialized tag parsing needs you can substitute the {#factory} # object with your own by setting {Library.default_factory= Library.default_factory} # to a new class with its own parsing methods before running YARD. This is useful # if you want to change the syntax of existing tags (@see, @since, etc.) # # @example Defining a custom tag # define_tag "Parameter", :param, :with_types_and_name # define_tag "Author", :author # @example Defining a custom directive # define_directive :method, :with_title_and_text, MethodDirective # @see DefaultFactory # @see define_tag # @see define_directive # @see Directive class Library class << self # @return [SymbolHash{Symbol=>String}] the map of tag names and their # respective display labels. attr_reader :labels # @!attribute instance # @return [Library] the main Library instance object. def instance @instance ||= new end # @!attribute default_factory # Replace the factory object responsible for parsing tags by setting # this to an object (or class) that responds to +parse_TAGNAME+ methods # where +TAGNAME+ is the name of the tag. # # You should set this value before performing any source parsing with # YARD, otherwise your factory class will not be used. # # @example # YARD::Tags::Library.default_factory = MyFactory # # @param [Class, Object] factory the factory that parses all tags # # @see DefaultFactory def default_factory @default_factory ||= DefaultFactory.new end def default_factory=(factory) @default_factory = factory.is_a?(Class) ? factory.new : factory end # Returns the factory method used to parse the tag text for a specific tag # # @param [Symbol] tag the tag name # @return [Symbol] the factory method name for the tag # @return [Class,Symbol] the Tag class to use to parse the tag # or the method to call on the factory class # @return [nil] if the tag is freeform text # @since 0.6.0 def factory_method_for(tag) @factory_methods[tag] end # Returns the factory method used to parse the tag text for a specific # directive # # @param [Symbol] directive the directive name # @return [Symbol] the factory method name for the tag # @return [Class,Symbol] the Tag class to use to parse the tag or # the methods to call on the factory class # @return [nil] if the tag is freeform text # @since 0.8.0 def factory_method_for_directive(directive) @directive_factory_classes[directive] end # Sets the list of tags to display when rendering templates. The order of # tags in the list is also significant, as it represents the order that # tags are displayed in templates. # # You can use the {Array#place} to insert new tags to be displayed in # the templates at specific positions: # # Library.visible_tags.place(:mytag).before(:return) # # @return [Array] a list of ordered tags # @since 0.6.0 attr_accessor :visible_tags # Sets the list of tags that should apply to any children inside the # namespace they are defined in. For instance, a "@since" tag should # apply to all methods inside a module it is defined in. Transitive # tags can be overridden by directly defining a tag on the child object. # # @return [Array] a list of transitive tags # @since 0.6.0 attr_accessor :transitive_tags # Sorts the labels lexically by their label name, often used when displaying # the tags. # # @return [Array, String] the sorted labels as an array of the tag name and label def sorted_labels labels.sort_by {|a| a.last.downcase } end # Convenience method to define a new tag using one of {Tag}'s factory methods, or the # regular {DefaultFactory#parse_tag} factory method if none is supplied. # # @!macro [attach] yard.tag # @!method $2_tag # @!visibility private # @yard.tag $2 [$3] $1 # @param [#to_s] label the label used when displaying the tag in templates # @param [#to_s] tag the tag name to create # @param [#to_s, Class] meth the {Tag} factory method to call when # creating the tag or the name of the class to directly create a tag for def define_tag(label, tag, meth = nil) tag_meth = tag_method_name(tag) if meth.is_a?(Class) && Tag > meth class_eval <<-eof, __FILE__, __LINE__ def #{tag_meth}(text) #{meth}.new(#{tag.inspect}, text) end eof else class_eval <<-eof, __FILE__, __LINE__ def #{tag_meth}(text) send_to_factory(#{tag.inspect}, #{meth.inspect}, text) end eof end @labels ||= SymbolHash.new(false) @labels.update(tag => label) @factory_methods ||= SymbolHash.new(false) @factory_methods.update(tag => meth) tag end # @macro [attach] yard.directive # @!method $1_directive # @!visibility private # @yard.directive $1 [$2] $-1 # @overload define_directive(tag, tag_meth = nil, directive_class) # Convenience method to define a new directive using a {Tag} factory # method and {Directive} subclass that implements the directive # callbacks. # # @param [#to_s] tag the tag name of the directive # @param [#to_s] tag_meth the tag factory method to use when # parsing tag information # @param [Class] the directive class that implements the # directive behaviour # @see define_tag def define_directive(tag, tag_meth = nil, directive_class = nil) directive_meth = directive_method_name(tag) if directive_class.nil? tag_meth, directive_class = nil, tag_meth end class_eval <<-eof, __FILE__, __LINE__ def #{directive_meth}(tag, parser) directive_call(tag, parser) end eof @factory_methods ||= SymbolHash.new(false) @factory_methods.update(tag => tag_meth) @directive_factory_classes ||= SymbolHash.new(false) @directive_factory_classes.update(tag => directive_class) tag end def tag_method_name(tag_name) tag_or_directive_method_name(tag_name) end def directive_method_name(tag_name) tag_or_directive_method_name(tag_name, 'directive') end private def tag_or_directive_method_name(tag_name, type = 'tag') "#{tag_name.to_s.gsub('.', '_')}_#{type}" end end private def send_to_factory(tag_name, meth, text) meth = meth.to_s send_name = "parse_tag" + (meth.empty? ? "" : "_" + meth) if @factory.respond_to?(send_name) arity = @factory.method(send_name).arity @factory.send(send_name, tag_name, text) else raise NoMethodError, "Factory #{@factory.class_name} does not implement factory method :#{meth}." end end # @return [Directive] def directive_call(tag, parser) meth = self.class.factory_method_for_directive(tag.tag_name) if meth <= Directive meth = meth.new(tag, parser) meth.call meth else meth.call(tag, parser) end end public # A factory class to handle parsing of tags, defaults to {default_factory} attr_accessor :factory def initialize(factory = Library.default_factory) self.factory = factory end # @param [#to_s] tag_name the name of the tag to look for # @return [Boolean] whether a tag by the given name is registered in # the library. def has_tag?(tag_name) tag_name && respond_to?(self.class.tag_method_name(tag_name)) end # Creates a new {Tag} object with a given tag name and data # @return [Tag] the newly created tag object def tag_create(tag_name, tag_buf) send(self.class.tag_method_name(tag_name), tag_buf) end # @param [#to_s] tag_name the name of the tag to look for # @return [Boolean] whether a directive by the given name is registered in # the library. def has_directive?(tag_name) tag_name && respond_to?(self.class.directive_method_name(tag_name)) end # Creates a new directive with tag information and a docstring parser # object. # @param [String] tag_name the name of the tag # @param [String] tag_buf the tag data # @param [DocstringParser] parser the parser object parsing the docstring # @return [Directive] the newly created directive def directive_create(tag_name, tag_buf, parser) meth = self.class.factory_method_for(tag_name) tag = send_to_factory(tag_name, meth, tag_buf) meth = self.class.directive_method_name(tag_name) send(meth, tag, parser) end # @!macro yard.tag.transitive # @note This tag is *transitive*. If it is applied on a # namespace (module or class), it will automatically be # applied to all children objects of that namespace unless # it is redefined on the child object. # Marks a class/module/method as abstract with optional # implementor information. # # @example # # @abstract Subclass and override {#run} to implement # # a custom Threadable class. # class Runnable # def run; raise NotImplementedError end # end define_tag "Abstract", :abstract # Declares the API that the object belongs to. Does not display in # output, but useful for performing queries (+yardoc --query+). Any text is # allowable in this tag, and there are no predefined values. # # @!macro yard.tag.transitive # @note The special name +@api private+ does display a notice in # documentation if it is listed, letting users know that the # method is not to be used by external components. # @example # class Post # # @api private # def reset_table!; table.flush end # end define_tag "API Visibility", :api # Declares a readwrite attribute on a Struct or class. # # @note This attribute is only applicable on class docstrings # @deprecated Use the more powerful {tag:!attribute} directive instead. # @example # # @attr [String] name the name of the structure # # @attr [Fixnum] size the size of the structure # class MyStruct < Struct; end define_tag "Attribute", :attr, :with_types_and_name # Declares a readonly attribute on a Struct or class. # # @note This attribute is only applicable on class docstrings # @deprecated Use the more powerful {tag:!attribute} directive instead. # @example # # @attr_reader [String] name the name of the structure # # @attr_reader [Fixnum] size the size of the structure # class MyStruct < Struct; end define_tag "Attribute Getter", :attr_reader, :with_types_and_name # Declares a writeonly attribute on a Struct or class. # # @note This attribute is only applicable on class docstrings # @deprecated Use the more powerful {tag:!attribute} directive instead. # @example # # @attr_reader [String] name the name of the structure # # @attr_reader [Fixnum] size the size of the structure # class MyStruct < Struct; end define_tag "Attribute Setter", :attr_writer, :with_types_and_name # List the author or authors of a class, module, or method. # # @example # # @author Foo Bar # class MyClass; end define_tag "Author", :author # Marks a method/class as deprecated with an optional description. # The description should be used to inform users of the recommended # migration path, and/or any useful information about why the object # was marked as deprecated. # # @example Deprecate a method with a replacement API # # @deprecated Use {#bar} instead. # def foo; end # @example Deprecate a method with no replacement # class Thread # # @deprecated Exiting a thread in this way is not reliable and # # can cause a program crash. # def kill; end # end define_tag "Deprecated", :deprecated # Show an example snippet of code for an object. The first line # is an optional title. # # @example # # @example Reverse a String # # "mystring".reverse #=> "gnirtsym" # def reverse; end # @yard.signature Optional title # Code block define_tag "Example", :example, :with_title_and_text # Adds an emphasized note at the top of the docstring for the object # # @example # # @note This method should only be used in outer space. # def eject; end # @see tag:todo define_tag "Note", :note # Describe an options hash in a method. The tag takes the # name of the options parameter first, followed by optional types, # the option key name, a default value for the key and a # description of the option. The default value should be placed within # parentheses and is optional (can be omitted). # # Note that a +@param+ tag need not be defined for the options # hash itself, though it is useful to do so for completeness. # # @example # # @param [Hash] opts the options to create a message with. # # @option opts [String] :subject The subject # # @option opts [String] :from ('nobody') From address # # @option opts [String] :to Recipient email # # @option opts [String] :body ('') The email's body # def send_email(opts = {}) end # @yard.signature name [Types] option_key (default_value) description define_tag "Options Hash", :option, :with_options # Describe that your method can be used in various # contexts with various parameters or return types. The first # line should declare the new method signature, and the following # indented tag data will be a new documentation string with its # own tags adding metadata for such an overload. # # @example # # @overload set(key, value) # # Sets a value on key # # @param [Symbol] key describe key param # # @param [Object] value describe value param # # @overload set(value) # # Sets a value on the default key +:foo+ # # @param [Object] value describe value param # def set(*args) end # @yard.signature method_signature(parameters) # Indented docstring for overload method define_tag "Overloads", :overload, OverloadTag # Documents a single method parameter with a given name, type # and optional description. # # @example # # @param [String] the URL of the page to download # def load_page(url) end define_tag "Parameters", :param, :with_types_and_name # Declares that the _logical_ visibility of an object is private. # In other words, it specifies that this method should be marked # private but cannot due to Ruby's visibility restrictions. This # exists for classes, modules and constants that do not obey Ruby's # visibility rules. For instance, an inner class might be considered # "private", though Ruby would make no such distinction. # # This tag is meant to be used in conjunction with the +--no-private+ # command-line option, and is required to actually remove these objects # from documentation output. See {file:README.md} for more information on # switches. # # If you simply want to set the API visibility of a method, you should # look at the {tag:api} tag instead. # # @note This method is not recommended for hiding undocumented or # "unimportant" methods. This tag should only be used to mark objects # private when Ruby visibility rules cannot do so. In Ruby 1.9.3, you # can use +private_constant+ to declare constants (like classes or # modules) as private, and should be used instead of +@private+. # @macro yard.tag.transitive # @example # # @private # class InteralImplementation; end # @see tag:api # @yard.signature define_tag "Private", :private # Describes that a method may raise a given exception, with # an optional description of what it may mean. # # @example # # @raise [AccountBalanceError] if the account does not have # # sufficient funds to perform the transaction # def withdraw(amount) end define_tag "Raises", :raise, :with_types # Describes the return value (and type or types) of a method. # You can list multiple return tags for a method in the case # where a method has distinct return cases. In this case, each # case should begin with "if ...". # # @example A regular return value # # @return [Fixnum] the size of the file # def size; @file.size end # @example A method returns an Array or a single object # # @return [String] if a single object was returned # # from the database. # # @return [Array] if multiple objects were # # returned. # def find(query) end define_tag "Returns", :return, :with_types # "See Also" references for an object. Accepts URLs or # other code objects with an optional description at the end. # Note that the URL or object will be automatically linked by # YARD and does not need to be formatted with markup. # # @example # # Synchronizes system time using NTP. # # @see http://ntp.org/documentation.html NTP Documentation # # @see NTPHelperMethods # class NTPUpdater; end define_tag "See Also", :see, :with_name # Lists the version that the object was first added. # # @!macro yard.tag.transitive # @example # # @since 1.2.4 # def clear_routes; end define_tag "Since", :since # Marks a TODO note in the object being documented. # For reference, objects with TODO items can be enumerated # from the command line with a simple command: # # !!!sh # mocker$ yard list --query '@todo' # lib/mocker/mocker.rb:15: Mocker # lib/mocker/report/html.rb:5: Mocker::Report::Html # # YARD can also be used to enumerate the TODO items from # a short script: # # !!!ruby # require 'yard' # YARD::Registry.load!.all.each do |o| # puts o.tag(:todo).text if o.tag(:todo) # end # # @example # # @todo Add support for Jabberwocky service. # # There is an open source Jabberwocky library available # # at http://jbrwcky.org that can be easily integrated. # class Wonderlander; end # @see tag:note define_tag "Todo Item", :todo # Lists the version of a class, module or method. This is # similar to a library version, but at finer granularity. # In some cases, version of specific modules, classes, methods # or generalized components might change independently between # releases. A version tag is used to infer the API compatibility # of a specific object. # # @example # # The public REST API for http://jbrwcky.org # # @version 2.0 # class JabberwockyAPI; end define_tag "Version", :version # Describes what a method might yield to a given block. # The types specifier list should not list types, but names # of the parameters yielded to the block. If you define # parameters with +@yieldparam+, you do not need to define # the parameters in the type specification of +@yield+ as # well. # # @example # # For a block {|a,b,c| ... } # # @yield [a, b, c] Gives 3 random numbers to the block # def provide3values(&block) yield(42, 42, 42) end # @see tag:yieldparam # @see tag:yieldreturn # @yard.signature [parameters] description define_tag "Yields", :yield, :with_types # Defines a parameter yielded by a block. If you define the # parameters with +@yieldparam+, you do not need to define # them via +@yield+ as well. # # @example # # @yieldparam [String] name the name that is yielded # def with_name(name) yield(name) end define_tag "Yield Parameters", :yieldparam, :with_types_and_name # Documents the value and type that the block is expected # to return to the method. # # @example # # @yieldreturn [Fixnum] the number to add 5 to. # def add5_block(&block) 5 + yield end # @see tag:return define_tag "Yield Returns", :yieldreturn, :with_types # @yard.signature [r | w | rw] attribute_name # Indented attribute docstring define_directive :attribute, :with_types_and_title, AttributeDirective # @yard.signature define_directive :endgroup, EndGroupDirective define_directive :group, GroupDirective # @yard.signature [attach | new] optional_name # Optional macro expansion data define_directive :macro, :with_types_and_title, MacroDirective # @yard.signature method_signature(parameters) # Indented method docstring define_directive :method, :with_title_and_text, MethodDirective # @yard.signature [language] code define_directive :parse, :with_types, ParseDirective # Sets the scope of a DSL method. Only applicable to DSL method # calls. Acceptable values are 'class' or 'instance' # @yard.signature class | instance define_directive :scope, ScopeDirective # Sets the visibility of a DSL method. Only applicable to # DSL method calls. Acceptable values are public, protected, or private. # @yard.signature public | protected | private define_directive :visibility, VisibilityDirective self.visible_tags = [:abstract, :deprecated, :note, :todo, :example, :overload, :param, :option, :yield, :yieldparam, :yieldreturn, :return, :raise, :see, :author, :since, :version] self.transitive_tags = [:since, :api] end end end yard-0.8.7.3/lib/yard/tags/ref_tag_list.rb0000644000004100000410000000113112261240652020304 0ustar www-datawww-datamodule YARD module Tags class RefTagList attr_accessor :owner, :tag_name, :name def initialize(tag_name, owner, name = nil) @owner = CodeObjects::Proxy === owner ? owner : P(owner) @tag_name = tag_name.to_s @name = name end def tags if owner.is_a?(CodeObjects::Base) o = owner.tags(tag_name) o = o.select {|t| t.name.to_s == name.to_s } if name o.each do |t| t.extend(RefTag) t.owner = owner end o else [] end end end end endyard-0.8.7.3/lib/yard/tags/overload_tag.rb0000644000004100000410000000356712261240652020327 0ustar www-datawww-datamodule YARD module Tags class OverloadTag < Tag attr_reader :signature, :parameters, :docstring def initialize(tag_name, text) super(tag_name, nil) parse_tag(text) parse_signature end def tag(name) docstring.tag(name) end def tags(name = nil) docstring.tags(name) end def has_tag?(name) docstring.has_tag?(name) end def object=(value) super(value) docstring.object = value docstring.tags.each {|tag| tag.object = value } end def name(prefix = false) return @name unless prefix object.scope == :class ? @name.to_s : "#{object.send(:sep)}#{@name}" end def method_missing(*args, &block) object.send(*args, &block) end def type object.type end def is_a?(other) object.is_a?(other) || self.class >= other.class || false end alias kind_of? is_a? private def parse_tag(text) @signature, text = *text.split(/\r?\n/, 2) @signature.strip! text ||= "" numspaces = text[/\A(\s*)/, 1].length text.gsub!(/^[ \t]{#{numspaces}}/, '') text.strip! @docstring = Docstring.new(text, nil) end def parse_signature if signature =~ /^(?:def\s)?\s*(#{CodeObjects::METHODMATCH})(?:(?:\s+|\s*\()(.*)(?:\)\s*$)?)?/m meth, args = $1, $2 meth.gsub!(/\s+/,'') # FIXME refactor this code to not make use of the Handlers::Base class (tokval_list should be moved) toks = YARD::Parser::Ruby::Legacy::TokenList.new(args) args = YARD::Handlers::Ruby::Legacy::Base.new(nil, nil).send(:tokval_list, toks, :all) args.map! {|a| k, v = *a.split('=', 2); [k.strip.to_s, (v ? v.strip : nil)] } if args @name = meth.to_sym @parameters = args end end end end end yard-0.8.7.3/lib/yard/tags/default_factory.rb0000644000004100000410000001547512261240652021035 0ustar www-datawww-datamodule YARD module Tags class DefaultFactory TYPELIST_OPENING_CHARS = '[({<' TYPELIST_CLOSING_CHARS = '>})]' # Parses tag text and creates a new tag with descriptive text # # @param tag_name the name of the tag to parse # @param [String] text the raw tag text # @return [Tag] a tag object with the tag_name and text values filled def parse_tag(tag_name, text) Tag.new(tag_name, text.strip) end # Parses tag text and creates a new tag with a key name and descriptive text # # @param tag_name the name of the tag to parse # @param [String] text the raw tag text # @return [Tag] a tag object with the tag_name, name and text values filled def parse_tag_with_name(tag_name, text) name, text = *extract_name_from_text(text) Tag.new(tag_name, text, nil, name) end # Parses tag text and creates a new tag with formally declared types and # descriptive text # # @param tag_name the name of the tag to parse # @param [String] text the raw tag text # @return [Tag] a tag object with the tag_name, types and text values filled def parse_tag_with_types(tag_name, text) name, types, text = *extract_types_and_name_from_text(text) raise TagFormatError, "cannot specify a name before type list for '@#{tag_name}'" if name Tag.new(tag_name, text, types) end # Parses tag text and creates a new tag with formally declared types, a key # name and descriptive text # # @param tag_name the name of the tag to parse # @param [String] text the raw tag text # @return [Tag] a tag object with the tag_name, name, types and text values filled def parse_tag_with_types_and_name(tag_name, text) name, types, text = *extract_types_and_name_from_text(text) name, text = *extract_name_from_text(text) unless name Tag.new(tag_name, text, types, name) end # Parses tag text and creates a new tag with formally declared types, a title # on the first line and descriptive text # # @param tag_name the name of the tag to parse # @param [String] text the raw tag text # @return [Tag] a tag object with the tag_name, name, types and text values filled def parse_tag_with_types_and_title(tag_name, text) name, types, text = *extract_types_and_name_from_text_unstripped(text) if name title, desc = name, text else title, desc = *extract_title_and_desc_from_text(text) end Tag.new(tag_name, desc, types, title) rescue TagFormatError Tag.new(tag_name, '', types, nil) end def parse_tag_with_title_and_text(tag_name, text) title, desc = *extract_title_and_desc_from_text(text) Tag.new(tag_name, desc, nil, title) end def parse_tag_with_types_name_and_default(tag_name, text) # Can't allow () in a default tag, otherwise the grammar is too ambiguous when types is omitted. open, close = TYPELIST_OPENING_CHARS.gsub('(', ''), TYPELIST_CLOSING_CHARS.gsub(')', '') name, types, text = *extract_types_and_name_from_text(text, open, close) name, text = *extract_name_from_text(text) unless name if text =~ /\A\(/ _, default, text = *extract_types_and_name_from_text(text, '(', ')') DefaultTag.new(tag_name, text, types, name, default) else DefaultTag.new(tag_name, text, types, name, nil) end end def parse_tag_with_options(tag_name, text) name, text = *extract_name_from_text(text) OptionTag.new(tag_name, name, parse_tag_with_types_name_and_default(tag_name, text)) end private # Extracts the name from raw tag text returning the name and remaining value # # @param [String] text the raw tag text # @return [Array] an array holding the name as the first element and the # value as the second element def extract_name_from_text(text) text.strip.split(/\s+/, 2) end def extract_title_and_desc_from_text(text) raise TagFormatError if text.nil? || text.empty? title, desc = nil, nil if text =~ /\A[ \t]\n/ desc = text else text = text.split(/\r?\n/) title = text.shift.squeeze(' ').strip desc = text.join("\n") end [title, desc] end # Parses a [], <>, {} or () block at the beginning of a line of text # into a list of comma delimited values. # # @example # obj.parse_types('[String, Array, nil]') # => [nil, ['String', 'Array', 'nil'], ""] # obj.parse_types('b A string') # => ['b', ['String'], 'A string'] # # @return [Array(String, Array, String)] the text before the type # list (or nil), followed by the type list parsed into an array of # strings, followed by the text following the type list. def extract_types_and_name_from_text(text, opening_types = TYPELIST_OPENING_CHARS, closing_types = TYPELIST_CLOSING_CHARS) before, list, text = *extract_types_and_name_from_text_unstripped(text, opening_types, closing_types) if list.nil? [nil, nil, text.strip] else [before ? before.strip : nil, list.map {|e| e.strip }, text.strip] end end def extract_types_and_name_from_text_unstripped(text, opening_types = TYPELIST_OPENING_CHARS, closing_types = TYPELIST_CLOSING_CHARS) s, e = 0, 0 before = '' list, level, seen_space, i = [''], 0, false, 0 last_seen = '' while i < text.length c = text[i, 1] if level > 0 && c == '#' && text[i+1..-1] =~ CodeObjects::METHODNAMEMATCH list.last << c + $& i += $&.length + 1 next elsif opening_types.include?(c) list.last << c if level > 0 s = i if level == 0 level += 1 elsif closing_types.include?(c) level -= 1 unless last_seen == '=' && c == '>' break e = i if level == 0 list.last << c elsif c == ',' && level == 1 list.push '' elsif c =~ /\S/ && level == 0 break e = i if seen_space && list == [''] before << c elsif c =~ /\s/ && level == 0 && !before.empty? seen_space = true elsif level >= 1 list.last << c end last_seen = c i += 1 end before = before.empty? ? nil : before if list.size == 1 && list.first == '' [nil, nil, text] else [before, list, text[(e+1)..-1]] end end end end endyard-0.8.7.3/lib/yard/registry_store.rb0000644000004100000410000002160412261240652017777 0ustar www-datawww-datarequire 'fileutils' module YARD # The data store for the {Registry}. # # @see Registry # @see Serializers::YardocSerializer class RegistryStore # @deprecated The registry no longer tracks proxy types attr_reader :proxy_types attr_reader :file, :checksums def initialize @file = nil @checksums = {} @store = {} @proxy_types = {} @object_types = {:root => [:root]} @notfound = {} @loaded_objects = 0 @available_objects = 0 @locales = {} @store[:root] = CodeObjects::RootObject.allocate @store[:root].send(:initialize, nil, :root) end # Gets a {CodeObjects::Base} from the store # # @param [String, Symbol] key the path name of the object to look for. # If it is empty or :root, returns the {#root} object. # @return [CodeObjects::Base, nil] a code object or nil if none is found def get(key) key = :root if key == '' key = key.to_sym return @store[key] if @store[key] return if @loaded_objects >= @available_objects # check disk return if @notfound[key] if obj = @serializer.deserialize(key) @loaded_objects += 1 put(key, obj) else @notfound[key] = true nil end end # Associates an object with a path # @param [String, Symbol] key the path name (:root or '' for root object) # @param [CodeObjects::Base] value the object to store # @return [CodeObjects::Base] returns +value+ def put(key, value) if key == '' @object_types[:root] = [:root] @store[:root] = value else @notfound.delete(key.to_sym) (@object_types[value.type] ||= []) << key.to_s if @store[key.to_sym] @object_types[@store[key.to_sym].type].delete(key.to_s) end @store[key.to_sym] = value end end alias [] get alias []= put # Deletes an object at a given path # @param [#to_sym] key the key to delete # @return [void] def delete(key) @store.delete(key.to_sym) end # Gets all path names from the store. Loads the entire database # if +reload+ is +true+ # # @param [Boolean] reload if false, does not load the entire database # before a lookup. # @return [Array] the path names of all the code objects def keys(reload = false) load_all if reload; @store.keys end # Gets all code objects from the store. Loads the entire database # if +reload+ is +true+ # # @param [Boolean] reload if false, does not load the entire database # before a lookup. # @return [Array] all the code objects def values(reload = false) load_all if reload; @store.values end # @param [Symbol] type the type to look for # @return [Array] a list of object paths with a given # {CodeObjects::Base#type} # @since 0.8.0 def paths_for_type(type, reload = false) load_all if reload @object_types[type] || [] end # @param [Symbol] type the type to look for # @return [Array] a list of objects with a given # {CodeObjects::Base#type} # @since 0.8.0 def values_for_type(type, reload = false) load_all if reload paths_for_type(type).map {|t| @store[t.to_sym] } end # @return [CodeObjects::RootObject] the root object def root; @store[:root] end # @param [String] name the locale name. # @return [I18n::Locale] the locale object for +name+. # @since 0.8.3 def locale(name) @locales[name] ||= load_locale(name) end # @param [String, nil] file the name of the yardoc db to load # @return [Boolean] whether the database was loaded def load(file = nil) @file = file @store = {} @proxy_types = {} @object_types = {} @notfound = {} @serializer = Serializers::YardocSerializer.new(@file) load_yardoc end # Loads the .yardoc file and loads all cached objects into memory # automatically. # # @param [String, nil] file the name of the yardoc db to load # @return [Boolean] whether the database was loaded # @see #load_all # @since 0.5.1 def load!(file = nil) if load(file) load_all true else false end end # Loads all cached objects into memory # @return [void] def load_all return unless @file return if @loaded_objects >= @available_objects log.debug "Loading entire database: #{@file} ..." objects = [] all_disk_objects.sort_by {|x| x.size }.each do |path| if obj = @serializer.deserialize(path, true) objects << obj end end objects.each do |obj| put(obj.path, obj) end @loaded_objects += objects.size log.debug "Loaded database (file='#{@file}' count=#{objects.size} total=#{@available_objects})" end # Saves the database to disk # @param [Boolean] merge if true, merges the data in memory with the # data on disk, otherwise the data on disk is deleted. # @param [String, nil] file if supplied, the name of the file to save to # @return [Boolean] whether the database was saved def save(merge = true, file = nil) if file && file != @file @file = file @serializer = Serializers::YardocSerializer.new(@file) end destroy unless merge sdb = Registry.single_object_db if sdb == true || sdb == nil @serializer.serialize(@store) else values(false).each do |object| @serializer.serialize(object) end end write_proxy_types write_object_types write_checksums true end # Deletes the .yardoc database on disk # # @param [Boolean] force if force is not set to true, the file/directory # will only be removed if it ends with .yardoc. This helps with # cases where the directory might have been named incorrectly. # @return [Boolean] true if the .yardoc database was deleted, false # otherwise. def destroy(force = false) if (!force && file =~ /\.yardoc$/) || force if File.file?(@file) # Handle silent upgrade of old .yardoc format File.unlink(@file) elsif File.directory?(@file) FileUtils.rm_rf(@file) end true else false end end protected def objects_path @serializer.objects_path end # @deprecated The registry no longer tracks proxy types def proxy_types_path @serializer.proxy_types_path end def checksums_path @serializer.checksums_path end def object_types_path @serializer.object_types_path end def load_yardoc return false unless @file if File.directory?(@file) # new format @loaded_objects = 0 @available_objects = all_disk_objects.size load_proxy_types load_checksums load_root load_object_types true elsif File.file?(@file) # old format load_yardoc_old true else false end end private def load_yardoc_old @store, @proxy_types = *Marshal.load(File.read_binary(@file)) end # @deprecated The registry no longer tracks proxy types def load_proxy_types return unless File.file?(proxy_types_path) @proxy_types = Marshal.load(File.read_binary(proxy_types_path)) end def load_object_types if File.file?(object_types_path) @object_types = Marshal.load(File.read_binary(object_types_path)) else # migrate db without object_types values.each do |object| (@object_types[object.type] ||= []) << object.path end end end def load_checksums return unless File.file?(checksums_path) lines = File.readlines(checksums_path).map do |line| line.strip.split(/\s+/) end @checksums = Hash[lines] end def load_root if root = @serializer.deserialize('root') @loaded_objects += 1 if root.is_a?(Hash) # single object db log.debug "Loading single object DB from .yardoc" @loaded_objects += (root.keys.size - 1) @store = root else # just the root object @store[:root] = root end end end def load_locale(name) locale = I18n::Locale.new(name) locale.load(Registry.po_dir) locale end def all_disk_objects Dir.glob(File.join(objects_path, '**/*')).select {|f| File.file?(f) } end # @deprecated The registry no longer tracks proxy types def write_proxy_types File.open!(proxy_types_path, 'wb') {|f| f.write(Marshal.dump(@proxy_types)) } end def write_object_types File.open!(object_types_path, 'wb') {|f| f.write(Marshal.dump(@object_types)) } end def write_checksums File.open!(checksums_path, 'w') do |f| @checksums.each {|k, v| f.puts("#{k} #{v}") } end end end end yard-0.8.7.3/lib/yard/core_ext/0000755000004100000410000000000012261240652016173 5ustar www-datawww-datayard-0.8.7.3/lib/yard/core_ext/string.rb0000644000004100000410000000302012261240652020021 0ustar www-datawww-dataclass String # Splits text into tokens the way a shell would, handling quoted # text as a single token. Use '\"' and "\'" to escape quotes and # '\\' to escape a backslash. # # @return [Array] an array representing the tokens def shell_split out = [""] state = :none escape_next = false quote = "" strip.split(//).each do |char| case state when :none, :space case char when /\s/ out << "" unless state == :space state = :space escape_next = false when "\\" if escape_next out.last << char escape_next = false else escape_next = true end when '"', "'" if escape_next out.last << char escape_next = false else state = char quote = "" end else state = :none out.last << char escape_next = false end when '"', "'" case char when '"', "'" if escape_next quote << char escape_next = false elsif char == state out.last << quote state = :none else quote << char end when '\\' if escape_next quote << char escape_next = false else escape_next = true end else quote << char escape_next = false end end end out end end yard-0.8.7.3/lib/yard/core_ext/hash.rb0000644000004100000410000000047212261240652017446 0ustar www-datawww-dataclass Hash class << self def create(*args) if args.first.is_a?(Array) && args.size == 1 obj = new args.first.each {|k, v| obj[k] = v } obj else create_186(*args) end end alias :create_186 :[] alias :[] :create end end if RUBY_VERSION < "1.8.7" yard-0.8.7.3/lib/yard/core_ext/module.rb0000644000004100000410000000077112261240652020012 0ustar www-datawww-dataclass Module # Returns the class name of a full module namespace path # # @example # module A::B::C; class_name end # => "C" # @return [String] the last part of a module path def class_name name.split("::").last end # Returns the module namespace path minus the class/module name # # @example # module A::B::C; namespace_name end # => "A::B" # @return [String] the namespace minus the class/module name def namespace_name name.split("::")[0..-2].join("::") end endyard-0.8.7.3/lib/yard/core_ext/file.rb0000644000004100000410000000360212261240652017440 0ustar www-datawww-datarequire 'fileutils' class File RELATIVE_PARENTDIR = '..' RELATIVE_SAMEDIR = '.' # @group Manipulating Paths # Turns a path +to+ into a relative path from starting # point +from+. The argument +from+ is assumed to be # a filename. To treat it as a directory, make sure it # ends in +File::SEPARATOR+ ('/' on UNIX filesystems). # # @param [String] from the starting filename # (or directory with +from_isdir+ set to +true+). # @param [String] to the final path that should be made relative. # @return [String] the relative path from +from+ to +to+. def self.relative_path(from, to) from = expand_path(from).split(SEPARATOR) to = expand_path(to).split(SEPARATOR) from.length.times do break if from[0] != to[0] from.shift; to.shift end from.pop join(*(from.map { RELATIVE_PARENTDIR } + to)) end # Cleans a path by removing extraneous '..', '.' and '/' characters # # @example Clean a path # File.cleanpath('a/b//./c/../e') # => "a/b/e" # @param [String] path the path to clean # @return [String] the sanitized path def self.cleanpath(path) path = path.split(SEPARATOR) path = path.inject([]) do |acc, comp| next acc if comp == RELATIVE_SAMEDIR if comp == RELATIVE_PARENTDIR && acc.size > 0 && acc.last != RELATIVE_PARENTDIR acc.pop next acc end acc << comp end File.join(*path) end # @group Reading Files # Forces opening a file (for writing) by first creating the file's directory # @param [String] file the filename to open # @since 0.5.2 def self.open!(file, *args, &block) dir = dirname(file) FileUtils.mkdir_p(dir) unless directory?(dir) open(file, *args, &block) end # Reads a file with binary encoding # @return [String] the ascii-8bit encoded data # @since 0.5.3 def self.read_binary(file) File.open(file, 'rb') {|f| f.read } end endyard-0.8.7.3/lib/yard/core_ext/insertion.rb0000644000004100000410000000371012261240652020533 0ustar www-datawww-data# The Insertion class inserts a value before or after another # value in a list. # # @example # Insertion.new([1, 2, 3], 4).before(3) # => [1, 2, 4, 3] class Insertion # Creates an insertion object on a list with a value to be # inserted. To finalize the insertion, call {#before} or # {#after} on the object. # # @param [Array] list the list to perform the insertion on # @param [Object] value the value to insert def initialize(list, value) @list, @values = list, (Array === value ? value : [value]) end # Inserts the value before +val+ # @param [Object] val the object the value will be inserted before # @param [Boolean] recursive look inside sublists def before(val, recursive = false) insertion(val, 0, recursive) end # Inserts the value after +val+. # # @example If subsections are ignored # Insertion.new([1, [2], 3], :X).after(1) # => [1, [2], :X, 3] # @param [Object] val the object the value will be inserted after # @param [Boolean] recursive look inside sublists def after(val, recursive = false) insertion(val, 1, recursive) end # Alias for {#before} with +recursive+ set to true # @since 0.6.0 def before_any(val) insertion(val, 0, true) end # Alias for {#after} with +recursive+ set to true # @since 0.6.0 def after_any(val) insertion(val, 1, true) end private # This method performs the actual insertion # # @param [Object] val the value to insert # @param [Fixnum] rel the relative index (0 or 1) of where the object # should be placed # @param [Boolean] recursive look inside sublists # @param [Array] list the list to place objects into def insertion(val, rel, recursive = false, list = @list) if recursive list.each do |item| next unless item.is_a?(Array) tmp = item.dup insertion(val, rel, recursive, item) return(list) unless item == tmp end end if index = list.index(val) list[index+rel,0] = @values end list end end yard-0.8.7.3/lib/yard/core_ext/array.rb0000644000004100000410000000110012261240652017626 0ustar www-datawww-dataclass Array # Places values before or after another object (by value) in # an array. This is used in tandem with the before and after # methods of the {Insertion} class. # # @example Places an item before another # [1, 2, 3].place(4).before(3) # => [1, 2, 4, 3] # @example Places an item after another # [:a, :b, :c].place(:x).after(:a) # => [:a, :x, :b, :c] # @param [Array] values value to insert # @return [Insertion] an insertion object to # @see Insertion#before # @see Insertion#after def place(*values) Insertion.new(self, values) end end yard-0.8.7.3/lib/yard/core_ext/symbol_hash.rb0000644000004100000410000000472312261240652021036 0ustar www-datawww-data# A subclass of Hash where all keys are converted into Symbols, and # optionally, all String values are converted into Symbols. class SymbolHash < Hash # Creates a new SymbolHash object # # @param [Boolean] symbolize_value converts any String values into Symbols # if this is set to +true+. def initialize(symbolize_value = true) @symbolize_value = symbolize_value end # @overload [](hash) # Creates a SymbolHash object from an existing Hash # # @example # SymbolHash['x' => 1, :y => 2] # => # # @param [Hash] hash the hash object # @return [SymbolHash] a new SymbolHash from a hash object # # @overload [](*list) # Creates a SymbolHash from an even list of keys and values # # @example # SymbolHash[key1, value1, key2, value2, ...] # @param [Array] list an even list of key followed by value # @return [SymbolHash] a new SymbolHash object def self.[](*hsh) obj = new; if hsh.size == 1 && hsh.first.is_a?(Hash) hsh.first.each {|k,v| obj[k] = v } else 0.step(hsh.size, 2) {|n| obj[hsh[n]] = hsh[n+1] } end obj end # Assigns a value to a symbolized key # @param [#to_sym] key the key # @param [Object] value the value to be assigned. If this is a String and # values are set to be symbolized, it will be converted into a Symbol. def []=(key, value) super(key.to_sym, value.instance_of?(String) && @symbolize_value ? value.to_sym : value) end # Accessed a symbolized key # @param [#to_sym] key the key to access # @return [Object] the value associated with the key def [](key) super(key.to_sym) end # Deleted a key and value associated with it # @param [#to_sym] key the key to delete # @return [void] def delete(key) super(key.to_sym) end # Tests if a symbolized key exists # @param [#to_sym] key the key to test # @return [Boolean] whether the key exists def has_key?(key) super(key.to_sym) end # Updates the object with the contents of another Hash object. # This method modifies the original SymbolHash object # # @param [Hash] hash the hash object to copy the values from # @return [SymbolHash] self def update(hash) hash.each {|k,v| self[k] = v }; self end alias_method :merge!, :update # Merges the contents of another hash into a new SymbolHash object # # @param [Hash] hash the hash of objects to copy # @return [SymbolHash] a new SymbolHash containing the merged data def merge(hash) dup.merge!(hash) end end yard-0.8.7.3/lib/yard/handlers/0000755000004100000410000000000012261240652016163 5ustar www-datawww-datayard-0.8.7.3/lib/yard/handlers/c/0000755000004100000410000000000012261240652016405 5ustar www-datawww-datayard-0.8.7.3/lib/yard/handlers/c/path_handler.rb0000644000004100000410000000041312261240652021361 0ustar www-datawww-dataclass YARD::Handlers::C::PathHandler < YARD::Handlers::C::Base MATCH = /([\w\.]+)\s* = \s*rb_path2class\s*\(\s*"([\w:]+)"\)/mx handles MATCH process do statement.source.scan(MATCH) do |var_name, path| namespaces[var_name] = P(path) end end end yard-0.8.7.3/lib/yard/handlers/c/mixin_handler.rb0000644000004100000410000000064112261240652021554 0ustar www-datawww-dataclass YARD::Handlers::C::MixinHandler < YARD::Handlers::C::Base MATCH = /rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/ handles MATCH statement_class BodyStatement process do statement.source.scan(MATCH) do |klass_var, mixin_var| namespace = namespace_for_variable(klass_var) ensure_loaded!(namespace) namespace.mixins(:instance) << namespace_for_variable(mixin_var) end end end yard-0.8.7.3/lib/yard/handlers/c/attribute_handler.rb0000644000004100000410000000065512261240652022440 0ustar www-datawww-dataclass YARD::Handlers::C::AttributeHandler < YARD::Handlers::C::Base MATCH = %r{rb_define_attr\s*\(\s*([\w\.]+),\s*"([^"]+)",\s*(0|1)\s*,\s*(0|1)\s*\)} handles MATCH process do return if ToplevelStatement == statement return if Comment === statement && statement.type != :multi statement.source.scan(MATCH) do |var_name, name, read, write| handle_attribute(var_name, name, read, write) end end end yard-0.8.7.3/lib/yard/handlers/c/init_handler.rb0000644000004100000410000000104312261240652021370 0ustar www-datawww-data# Handles the Init_Libname() method class YARD::Handlers::C::InitHandler < YARD::Handlers::C::Base MATCH = %r{\A\s*(?:static\s+)?void\s+(?:[Ii]nit_)?(\w+)\s*} handles MATCH statement_class ToplevelStatement process do parse_block if decl = statement.declaration[MATCH, 1] ns = namespace_for_variable(decl) if ns.is_a?(YARD::CodeObjects::NamespaceObject) && ns.docstring.blank? if statement.comments register_docstring(ns, statement.comments.source, statement) end end end end end yard-0.8.7.3/lib/yard/handlers/c/class_handler.rb0000644000004100000410000000142412261240652021535 0ustar www-datawww-dataclass YARD::Handlers::C::ClassHandler < YARD::Handlers::C::Base MATCH1 = /([\w\.]+)\s* = \s*(?:rb_define_class|boot_defclass)\s* \( \s*"([\w:]+)", \s*(\w+|0)\s* \)/mx MATCH2 = /([\w\.]+)\s* = \s*rb_define_class_under\s* \( \s*(\w+), \s*"(\w+)"(?:, \s*([\w\*\s\(\)\.\->]+)\s*)? # for SWIG \s*\)/mx handles MATCH1 handles MATCH2 statement_class BodyStatement process do statement.source.scan(MATCH1) do |var_name, class_name, parent| handle_class(var_name, class_name, parent) end statement.source.scan(MATCH2) do |var_name, in_module, class_name, parent| handle_class(var_name, class_name, parent, in_module) end end end yard-0.8.7.3/lib/yard/handlers/c/method_handler.rb0000644000004100000410000000224512261240652021712 0ustar www-datawww-dataclass YARD::Handlers::C::MethodHandler < YARD::Handlers::C::Base MATCH1 = %r{rb_define_ ( singleton_method | method | module_function | private_method ) \s*\(\s*([\w\.]+), \s*"([^"]+)", \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\(|\(\w+\))?(\w+)\)?, \s*(-?\w+)\s*\)}xm MATCH2 = %r{rb_define_global_function\s*\( \s*"([^"]+)", \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\(|\(\w+\))?(\w+)\)?, \s*(-?\w+)\s*\)}xm handles MATCH1 handles MATCH2 statement_class BodyStatement process do statement.source.scan(MATCH1) do |type, var_name, name, func_name, param_count| break if var_name == "ruby_top_self" break if var_name == "nstr" break if var_name == "envtbl" var_name = "rb_cObject" if var_name == "rb_mKernel" handle_method(type, var_name, name, func_name) end statement.source.scan(MATCH2) do |name, func_name, param_count| handle_method("method", "rb_mKernel", name, func_name) end end end yard-0.8.7.3/lib/yard/handlers/c/struct_handler.rb0000644000004100000410000000056612261240652021762 0ustar www-datawww-dataclass YARD::Handlers::C::StructHandler < YARD::Handlers::C::Base MATCH = /([\w\.]+)\s*=\s*(?:rb_struct_define_without_accessor)\s* \(\s*"([\w:]+)"\s*,\s*(\w+)\s*/mx handles MATCH statement_class BodyStatement process do statement.source.scan(MATCH) do |var_name, class_name, parent| handle_class(var_name, class_name, parent) end end end yard-0.8.7.3/lib/yard/handlers/c/module_handler.rb0000644000004100000410000000105712261240652021717 0ustar www-datawww-dataclass YARD::Handlers::C::ModuleHandler < YARD::Handlers::C::Base MATCH1 = /([\w\.]+)\s* = \s*rb_define_module\s*\(\s*"([\w:]+)"\s*\)/mx MATCH2 = /([\w\.]+)\s* = \s*rb_define_module_under\s*\(\s*(\w+),\s*"(\w+)"\s*\)/mx handles MATCH1 handles MATCH2 statement_class BodyStatement process do statement.source.scan(MATCH1) do |var_name, module_name| handle_module(var_name, module_name) end statement.source.scan(MATCH2) do |var_name, in_module, module_name| handle_module(var_name, module_name, in_module) end end end yard-0.8.7.3/lib/yard/handlers/c/alias_handler.rb0000644000004100000410000000067012261240652021523 0ustar www-datawww-dataclass YARD::Handlers::C::AliasHandler < YARD::Handlers::C::Base MATCH = %r{rb_define_alias \s*\(\s*([\w\.]+), \s*"([^"]+)", \s*"([^"]+)"\s*\)}xm handles MATCH statement_class BodyStatement process do statement.source.scan(MATCH) do |var_name, new_name, old_name| var_name = "rb_cObject" if var_name == "rb_mKernel" handle_alias(var_name, new_name, old_name) end end end yard-0.8.7.3/lib/yard/handlers/c/handler_methods.rb0000644000004100000410000001465512261240652022105 0ustar www-datawww-datamodule YARD module Handlers module C module HandlerMethods include Parser::C include CodeObjects def handle_class(var_name, class_name, parent, in_module = nil) parent = nil if parent == "0" namespace = in_module ? namespace_for_variable(in_module) : Registry.root register ClassObject.new(namespace, class_name) do |obj| if parent parent_class = namespace_for_variable(parent) if parent_class.is_a?(Proxy) obj.superclass = "::#{parent_class.path}" obj.superclass.type = :class else obj.superclass = parent_class end end namespaces[var_name] = obj register_file_info(obj, statement.file, statement.line) end end def handle_module(var_name, module_name, in_module = nil) namespace = in_module ? namespace_for_variable(in_module) : Registry.root register ModuleObject.new(namespace, module_name) do |obj| namespaces[var_name] = obj register_file_info(obj, statement.file, statement.line) end end def handle_method(scope, var_name, name, func_name, source_file = nil) visibility = :public case scope when "singleton_method"; scope = :class when "module_function"; scope = :module when "private_method"; scope = :instance; visibility = :private else; scope = :instance end namespace = namespace_for_variable(var_name) return if namespace.nil? # XXX: raise UndocumentableError might be too noisy. register MethodObject.new(namespace, name, scope) do |obj| register_visibility(obj, visibility) find_method_body(obj, func_name) obj.add_tag(Tags::Tag.new(:return, '', 'Boolean')) if name =~ /\?$/ end end def handle_attribute(var_name, name, read, write) values = {:read => read.to_i, :write => write.to_i} {:read => name, :write => "#{name}="}.each do |type, meth_name| next unless values[type] > 0 obj = handle_method(:instance, var_name, meth_name, nil) obj.namespace.attributes[:instance][name] ||= SymbolHash[:read => nil, :write => nil] obj.namespace.attributes[:instance][name][type] = obj end end def handle_alias(var_name, new_name, old_name) namespace = namespace_for_variable(var_name) return if namespace.nil? new_meth, old_meth = new_name.to_sym, old_name.to_sym old_obj = namespace.child(:name => old_meth, :scope => :instance) new_obj = register MethodObject.new(namespace, new_meth, :instance) do |o| register_visibility(o, visibility) register_file_info(o, statement.file, statement.line) end if old_obj new_obj.signature = old_obj.signature new_obj.source = old_obj.source new_obj.docstring = old_obj.docstring new_obj.docstring.object = new_obj else new_obj.signature = "def #{new_meth}" # this is all we know. end namespace.aliases[new_obj] = old_meth end def handle_constants(type, var_name, const_name, value) return unless type == 'const' namespace = namespace_for_variable(var_name) register ConstantObject.new(namespace, const_name) do |obj| obj.source_type = :c obj.value = value register_file_info(obj, statement.file, statement.line) find_constant_docstring(obj) end end private def find_constant_docstring(object) comment = nil # look inside overrides for declaration value override_comments.each do |name, override_comment| next unless override_comment.file == statement.file just_const_name = name.gsub(/\A.+::/, '') if object.path == name || object.name.to_s == just_const_name comment = override_comment.source stmt = override_comment break end end # use any comments on this statement as a last resort if comment.nil? && statement.comments && statement.comments.source =~ /\S/ comment = statement.comments.source stmt = statement.comments end # In the case of rb_define_const, the definition and comment are in # "/* definition: comment */" form. The literal ':' and '\' characters # can be escaped with a backslash. if comment comment.scan(/\A\s*(.*?[^\s\\]):\s*(.+)/m) do |new_value, new_comment| object.value = new_value.gsub(/\\:/, ':') comment = new_comment end register_docstring(object, comment, stmt) end end def find_method_body(object, symbol) file, in_file = statement.file, false if statement.comments && statement.comments.source =~ /\A\s*in (\S+)\Z/ file, in_file = $1, true process_file(file, object) end if src_stmt = symbols[symbol] register_file_info(object, src_stmt.file, src_stmt.line, true) register_source(object, src_stmt) unless src_stmt.comments.nil? || src_stmt.comments.source.empty? register_docstring(object, src_stmt.comments.source, src_stmt) return # found docstring end end # found source (possibly) but no docstring # so look in overrides override_comments.each do |name, override_comment| next unless override_comment.file == file name = name.gsub(/::([^:]+?)\Z/, '.\1') just_method_name = name.gsub(/\A.+(#|::|\.)/, '') just_method_name = 'initialize' if just_method_name == 'new' if object.path == name || object.name.to_s == just_method_name register_docstring(object, override_comment.source, override_comment) return end end # use any comments on this statement as a last resort if !in_file && statement.comments && statement.comments.source =~ /\S/ register_docstring(object, statement.comments.source, statement) end end end end end end yard-0.8.7.3/lib/yard/handlers/c/override_comment_handler.rb0000644000004100000410000000152212261240652023770 0ustar www-datawww-data# Parses comments class YARD::Handlers::C::OverrideCommentHandler < YARD::Handlers::C::Base handles %r{.} statement_class Comment process do return if statement.overrides.empty? statement.overrides.each do |type, name| override_comments << [name, statement] obj = nil case type when :class name, superclass = *name.split(/\s*<\s*/) obj = YARD::CodeObjects::ClassObject.new(:root, name) obj.superclass = "::#{superclass}" if superclass when :module obj = YARD::CodeObjects::ModuleObject.new(:root, name) end register(obj) end end def register_docstring(object, docstring = statement.source, stmt = statement) super end def register_file_info(object, file = parser.file, line = statement.line, comments = statement.comments) super end end yard-0.8.7.3/lib/yard/handlers/c/constant_handler.rb0000644000004100000410000000063412261240652022263 0ustar www-datawww-dataclass YARD::Handlers::C::ConstantHandler < YARD::Handlers::C::Base MATCH = %r{\brb_define_((?:readonly_)?variable|(?:global_)?const) \s*\((?:\s*(\w+),)?\s*"(\w+)",\s*(.*?)\s*\)\s*;}xm handles MATCH statement_class BodyStatement process do statement.source.scan(MATCH) do |type, var_name, const_name, value| handle_constants(type, var_name, const_name, value) end end end yard-0.8.7.3/lib/yard/handlers/c/base.rb0000644000004100000410000000576412261240652017660 0ustar www-datawww-datamodule YARD module Handlers module C class Base < Handlers::Base include YARD::Parser::C include HandlerMethods # @return [Boolean] whether the handler handles this statement def self.handles?(statement, processor) processor.globals.cruby_processed_files ||= {} processor.globals.cruby_processed_files[processor.file] = true if statement.respond_to? :declaration src = statement.declaration else src = statement.source end handlers.any? do |a_handler| statement_class >= statement.class && case a_handler when String src == a_handler when Regexp src =~ a_handler end end end def self.statement_class(type = nil) type ? @statement_class = type : (@statement_class || Statement) end # @group Registering objects def register_docstring(object, docstring = nil, stmt = nil) super(object, docstring, stmt) if docstring end def register_file_info(object, file = nil, line = nil, comments = nil) super(object, file, line, comments) if file end def register_source(object, source = nil, type = nil) super(object, source, type) if source end def register_visibility(object, visibility = nil) super(object, visibility) if visibility end # @group Looking up Symbol and Var Values def symbols globals.cruby_symbols ||= {} end def override_comments globals.cruby_override_comments ||= [] end def namespace_for_variable(var) return namespaces[var] if namespaces[var] var = remove_var_prefix(var) var.empty? ? nil : P(var) end def namespaces globals.cruby_namespaces ||= {} end def processed_files globals.cruby_processed_files ||= {} end # @group Parsing an Inner Block def parse_block(opts = {}) return if !statement.block || statement.block.empty? push_state(opts) do parser.process(statement.block) end end # @group Processing other files def process_file(file, object) file = File.cleanpath(file) return if processed_files[file] processed_files[file] = file begin log.debug "Processing embedded call to C source #{file}..." globals.ordered_parser.files.delete(file) if globals.ordered_parser parser.process(Parser::C::CParser.new(File.read(file), file).parse) rescue Errno::ENOENT log.warn "Missing source file `#{file}' when parsing #{object}" end end # @endgroup private def remove_var_prefix(var) var.gsub(/^rb_[mc]|^[a-z_]+/, '') end end end end end yard-0.8.7.3/lib/yard/handlers/c/symbol_handler.rb0000644000004100000410000000053312261240652021735 0ustar www-datawww-data# Keeps track of function bodies for symbol lookup during Ruby method declarations class YARD::Handlers::C::SymbolHandler < YARD::Handlers::C::Base MATCH = %r{\A\s*(?:(?:static|SWIGINTERN)\s+)?(?:intern\s+)?VALUE\s+(\w+)\s*\(} handles MATCH statement_class ToplevelStatement process { symbols[statement.source[MATCH, 1]] = statement } end yard-0.8.7.3/lib/yard/handlers/processor.rb0000644000004100000410000001725712261240652020543 0ustar www-datawww-datarequire 'ostruct' module YARD module Handlers # Iterates over all statements in a file and delegates them to the # {Handlers::Base} objects that are registered to handle the statement. # # This class is passed to each handler and keeps overall processing state. # For example, if the {#visibility} is set in a handler, all following # statements will have access to this state. This allows "public", # "protected" and "private" statements to be handled in classes and modules. # In addition, the {#namespace} can be set during parsing to control # where objects are being created from. You can also access extra stateful # properties that any handler can set during the duration of the post # processing of a file from {#extra_state}. If you need to access state # across different files, look at {#globals}. # # @see Handlers::Base class Processor class << self # Registers a new namespace for handlers of the given type. # @since 0.6.0 def register_handler_namespace(type, ns) namespace_for_handler[type] = ns end # @return [Hash] a list of registered parser type extensions # @private # @since 0.6.0 attr_reader :namespace_for_handler undef namespace_for_handler def namespace_for_handler; @@parser_type_extensions ||= {} end end register_handler_namespace :ruby, Ruby register_handler_namespace :ruby18, Ruby::Legacy register_handler_namespace :c, C # @return [String] the filename attr_accessor :file # @return [CodeObjects::NamespaceObject] the current namespace attr_accessor :namespace # @return [Symbol] the current visibility (public, private, protected) attr_accessor :visibility # @return [Symbol] the current scope (class, instance) attr_accessor :scope # @return [CodeObjects::Base, nil] unlike the namespace, the owner # is a non-namespace object that should be stored between statements. # For instance, when parsing a method body, the {CodeObjects::MethodObject} # is set as the owner, in case any extra method information is processed. attr_accessor :owner # @return [Symbol] the parser type (:ruby, :ruby18, :c) attr_accessor :parser_type # Handlers can share state for the entire post processing stage through # this attribute. Note that post processing stage spans multiple files. # To share state only within a single file, use {#extra_state} # # @example Sharing state among two handlers # class Handler1 < YARD::Handlers::Ruby::Base # handles :class # process { globals.foo = :bar } # end # # class Handler2 < YARD::Handlers::Ruby::Base # handles :method # process { puts globals.foo } # end # @return [OpenStruct] global shared state for post-processing stage # @see #extra_state attr_accessor :globals # Share state across different handlers inside of a file. # This attribute is similar to {#visibility}, {#scope}, {#namespace} # and {#owner}, in that they all maintain state across all handlers # for the entire source file. Use this attribute to store any data # your handler might need to save during the parsing of a file. If # you need to save state across files, see {#globals}. # # @return [OpenStruct] an open structure that can store arbitrary data # @see #globals attr_accessor :extra_state # Creates a new Processor for a +file+. # @param [SourceParser] parser the parser used to initialize the processor def initialize(parser) @file = parser.file || "(stdin)" @namespace = YARD::Registry.root @visibility = :public @scope = :instance @owner = @namespace @parser_type = parser.parser_type @handlers_loaded = {} @globals = parser.globals || OpenStruct.new @extra_state = OpenStruct.new load_handlers end # Processes a list of statements by finding handlers to process each # one. # # @param [Array] statements a list of statements # @return [void] def process(statements) statements.each_with_index do |stmt, index| find_handlers(stmt).each do |handler| begin handler.new(self, stmt).process rescue HandlerAborted => abort log.debug "#{handler.to_s} cancelled from #{caller.last}" log.debug "\tin file '#{file}':#{stmt.line}:\n\n" + stmt.show + "\n" rescue NamespaceMissingError => missingerr log.warn "The #{missingerr.object.type} #{missingerr.object.path} has not yet been recognized." log.warn "If this class/method is part of your source tree, this will affect your documentation results." log.warn "You can correct this issue by loading the source file for this object before `#{file}'" log.warn rescue Parser::UndocumentableError => undocerr log.warn "in #{handler.to_s}: Undocumentable #{undocerr.message}" log.warn "\tin file '#{file}':#{stmt.line}:\n\n" + stmt.show + "\n" rescue => e log.error "Unhandled exception in #{handler.to_s}:" log.error " in `#{file}`:#{stmt.line}:\n\n#{stmt.show}\n" log.backtrace(e) end end end end # Continue parsing the remainder of the files in the +globals.ordered_parser+ # object. After the remainder of files are parsed, processing will continue # on the current file. # # @return [void] # @see Parser::OrderedParser def parse_remaining_files if globals.ordered_parser globals.ordered_parser.parse log.debug("Re-processing #{@file}...") end end # Searches for all handlers in {Base.subclasses} that match the +statement+ # # @param statement the statement object to match. # @return [Array] a list of handlers to process the statement with. def find_handlers(statement) Base.subclasses.find_all do |handler| handler_base_class > handler && (handler.namespace_only? ? owner.is_a?(CodeObjects::NamespaceObject) : true) && handles?(handler, statement) end end private def handles?(handler, statement) return false unless handler.matches_file?(file) if handler.method(:handles?).arity == 1 handler.handles?(statement) elsif [-1, 2].include?(handler.method(:handles?).arity) handler.handles?(statement, self) end end # Returns the handler base class # @return [Base] the base class def handler_base_class handler_base_namespace.const_get(:Base) end # The module holding the handlers to be loaded # # @return [Module] the module containing the handlers depending on # {#parser_type}. def handler_base_namespace self.class.namespace_for_handler[parser_type] end # Loads handlers from {#handler_base_namespace}. This ensures that # Ruby1.9 handlers are never loaded into 1.8; also lowers the amount # of modules that are loaded # @return [void] def load_handlers return if @handlers_loaded[parser_type] handler_base_namespace.constants.each do |c| const = handler_base_namespace.const_get(c) unless Handlers::Base.subclasses.include?(const) Handlers::Base.subclasses << const end end @handlers_loaded[parser_type] = true end end end endyard-0.8.7.3/lib/yard/handlers/base.rb0000644000004100000410000005470012261240652017430 0ustar www-datawww-datamodule YARD module Handlers # Raise this error when a handler should exit before completing. # The exception will be silenced, allowing the next handler(s) in the # queue to be executed. # @since 0.8.4 class HandlerAborted < ::RuntimeError; end # Raised during processing phase when a handler needs to perform # an operation on an object's namespace but the namespace could # not be resolved. class NamespaceMissingError < Parser::UndocumentableError # The object the error occurred on # @return [CodeObjects::Base] a code object attr_accessor :object def initialize(object) @object = object end end # Handlers are pluggable semantic parsers for YARD's code generation # phase. They allow developers to control what information gets # generated by YARD, giving them the ability to, for instance, document # any Ruby DSLs that a customized framework may use. A good example # of this would be the ability to document and generate meta data for # the 'describe' declaration of the RSpec testing framework by simply # adding a handler for such a keyword. Similarly, any Ruby API that # takes advantage of class level declarations could add these to the # documentation in a very explicit format by treating them as first- # class objects in any outputted documentation. # # == Overview of a Typical Handler Scenario # # Generally, a handler class will declare a set of statements which # it will handle using the {handles} class declaration. It will then # implement the {#process} method to do the work. The processing would # usually involve the manipulation of the {#namespace}, {#owner} # {CodeObjects::Base code objects} or the creation of new ones, in # which case they should be registered by {#register}, a method that # sets some basic attributes for the new objects. # # Handlers are usually simple and take up to a page of code to process # and register a new object or add new attributes to the current +namespace+. # # == Setting up a Handler for Use # # A Handler is automatically registered when it is subclassed from the # base class. The only other thing that needs to be done is to specify # which statement the handler will process. This is done with the +handles+ # declaration, taking either a {Parser::Ruby::Legacy::RubyToken}, {String} or `Regexp`. # Here is a simple example which processes module statements. # # class MyModuleHandler < YARD::Handlers::Base # handles TkMODULE # # def process # # do something # end # end # # == Processing Handler Data # # The goal of a specific handler is really up to the developer, and as # such there is no real guideline on how to process the data. However, # it is important to know where the data is coming from to be able to use # it. # # === +statement+ Attribute # # The +statement+ attribute pertains to the {Parser::Ruby::Legacy::Statement} object # containing a set of tokens parsed in by the parser. This is the main set # of data to be analyzed and processed. The comments attached to the statement # can be accessed by the {Parser::Ruby::Legacy::Statement#comments} method, but generally # the data to be processed will live in the +tokens+ attribute. This list # can be converted to a +String+ using +#to_s+ to parse the data with # regular expressions (or other text processing mechanisms), if needed. # # === +namespace+ Attribute # # The +namespace+ attribute is a {CodeObjects::NamespaceObject namespace object} # which represents the current namespace that the parser is in. For instance: # # module SomeModule # class MyClass # def mymethod; end # end # end # # If a handler was to parse the 'class MyClass' statement, it would # be necessary to know that it belonged inside the SomeModule module. # This is the value that +namespace+ would return when processing such # a statement. If the class was then entered and another handler was # called on the method, the +namespace+ would be set to the 'MyClass' # code object. # # === +owner+ Attribute # # The +owner+ attribute is similar to the +namespace+ attribute in that # it also follows the scope of the code during parsing. However, a namespace # object is loosely defined as a module or class and YARD has the ability # to parse beyond module and class blocks (inside methods, for instance), # so the +owner+ attribute would not be limited to modules and classes. # # To put this into context, the example from above will be used. If a method # handler was added to the mix and decided to parse inside the method body, # the +owner+ would be set to the method object but the namespace would remain # set to the class. This would allow the developer to process any method # definitions set inside a method (def x; def y; 2 end end) by adding them # to the correct namespace (the class, not the method). # # In summary, the distinction between +namespace+ and +owner+ can be thought # of as the difference between first-class Ruby objects (namespaces) and # second-class Ruby objects (methods). # # === +visibility+ and +scope+ Attributes # # Mainly needed for parsing methods, the +visibility+ and +scope+ attributes # refer to the public/protected/private and class/instance values (respectively) # of the current parsing position. # # == Parsing Blocks in Statements # # In addition to parsing a statement and creating new objects, some # handlers may wish to continue parsing the code inside the statement's # block (if there is one). In this context, a block means the inside # of any statement, be it class definition, module definition, if # statement or classic 'Ruby block'. # # For example, a class statement would be "class MyClass" and the block # would be a list of statements including the method definitions inside # the class. For a class handler, the programmer would execute the # {#parse_block} method to continue parsing code inside the block, with # the +namespace+ now pointing to the class object the handler created. # # YARD has the ability to continue into any block: class, module, method, # even if statements. For this reason, the block parsing method must be # invoked explicitly out of efficiency sake. # # @abstract Subclass this class to provide a handler for YARD to use # during the processing phase. # # @see CodeObjects::Base # @see CodeObjects::NamespaceObject # @see handles # @see #namespace # @see #owner # @see #register # @see #parse_block class Base # For accessing convenience, eg. "MethodObject" # instead of the full qualified namespace include YARD::CodeObjects include Parser class << self # Clear all registered subclasses. Testing purposes only # @return [void] def clear_subclasses @@subclasses = [] end # Returns all registered handler subclasses. # @return [Array] a list of handlers def subclasses @@subclasses ||= [] end def inherited(subclass) @@subclasses ||= [] @@subclasses << subclass end # Declares the statement type which will be processed # by this handler. # # A match need not be unique to a handler. Multiple # handlers can process the same statement. However, # in this case, care should be taken to make sure that # {#parse_block} would only be executed by one of # the handlers, otherwise the same code will be parsed # multiple times and slow YARD down. # # @param [Parser::RubyToken, Symbol, String, Regexp] matches # statements that match the declaration will be # processed by this handler. A {String} match is # equivalent to a +/\Astring/+ regular expression # (match from the beginning of the line), and all # token matches match only the first token of the # statement. # def handles(*matches) (@handlers ||= []).push(*matches) end # This class is implemented by {Ruby::Base} and {Ruby::Legacy::Base}. # To implement a base handler class for another language, implement # this method to return true if the handler should process the given # statement object. Use {handlers} to enumerate the matchers declared # for the handler class. # # @param statement a statement object or node (depends on language type) # @return [Boolean] whether or not this handler object should process # the given statement def handles?(statement) raise NotImplementedError, "override #handles? in a subclass" end # @return [Array] a list of matchers for the handler object. # @see handles? def handlers @handlers ||= [] end # Declares that the handler should only be called when inside a # {CodeObjects::NamespaceObject}, not a method body. # # @return [void] def namespace_only @namespace_only = true end # @return [Boolean] whether the handler should only be processed inside # a namespace. def namespace_only? (@namespace_only ||= false) ? true : false end # Declares that a handler should only be called when inside a filename # by its basename or a regex match for the full path. # # @param [String, Regexp] filename a matching filename or regex # @return [void] # @since 0.6.2 def in_file(filename) (@in_files ||= []) << filename end # @return [Boolean] whether the filename matches the declared file # match for a handler. If no file match is specified, returns true. # @since 0.6.2 def matches_file?(filename) @in_files ||= nil # avoid ruby warnings return true unless @in_files @in_files.any? do |in_file| case in_file when String File.basename(filename) == in_file when Regexp filename =~ in_file else true end end end # Generates a +process+ method, equivalent to +def process; ... end+. # Blocks defined with this syntax will be wrapped inside an anonymous # module so that the handler class can be extended with mixins that # override the +process+ method without alias chaining. # # @!macro yard.handlers.process # @!method process # Main processing callback # @return [void] # @see #process # @return [void] # @since 0.5.4 def process(&block) mod = Module.new mod.send(:define_method, :process, &block) include mod end end def initialize(source_parser, stmt) @parser = source_parser @statement = stmt end # The main handler method called by the parser on a statement # that matches the {handles} declaration. # # Subclasses should override this method to provide the handling # functionality for the class. # # @return [Array, CodeObjects::Base, Object] # If this method returns a code object (or a list of them), # they are passed to the +#register+ method which adds basic # attributes. It is not necessary to return any objects and in # some cases you may want to explicitly avoid the returning of # any objects for post-processing by the register method. # # @see handles # @see #register # def process raise NotImplementedError, "#{self} did not implement a #process method for handling." end # Parses the semantic "block" contained in the statement node. # # @abstract Subclasses should call {Processor#process parser.process} def parse_block(*args) raise NotImplementedError, "#{self} did not implement a #parse_block method for handling" end # @return [Processor] the processor object that manages all global state # during handling. attr_reader :parser # @return [Object] the statement object currently being processed. Usually # refers to one semantic language statement, though the strict definition # depends on the parser used. attr_reader :statement # (see Processor#owner) attr_accessor :owner # (see Processor#namespace) attr_accessor :namespace # (see Processor#visibility) attr_accessor :visibility # (see Processor#scope) attr_accessor :scope # (see Processor#globals) attr_reader :globals # (see Processor#extra_state) attr_reader :extra_state undef owner, owner=, namespace, namespace= undef visibility, visibility=, scope, scope= undef globals, extra_state def owner; parser.owner end def owner=(v) parser.owner=(v) end def namespace; parser.namespace end def namespace=(v); parser.namespace=(v) end def visibility; parser.visibility end def visibility=(v); parser.visibility=(v) end def scope; parser.scope end def scope=(v); parser.scope=(v) end def globals; parser.globals end def extra_state; parser.extra_state end # Aborts a handler by raising {Handlers::HandlerAborted}. # An exception will only be logged in debugging mode for # this kind of handler exit. # # @since 0.8.4 def abort! raise Handlers::HandlerAborted end # Executes a given block with specific state values for {#owner}, # {#namespace} and {#scope}. # # @param [Proc] block the block to execute with specific state # @option opts [CodeObjects::NamespaceObject] :namespace (value of #namespace) # the namespace object that {#namespace} will be equal to for the # duration of the block. # @option opts [Symbol] :scope (:instance) # the scope for the duration of the block. # @option opts [CodeObjects::Base] :owner (value of #owner) # the owner object (method) for the duration of the block # @yield a block to execute with the given state values. def push_state(opts = {}, &block) opts = { :namespace => namespace, :scope => :instance, :owner => owner || namespace, :visibility => nil }.update(opts) ns, vis, sc, oo = namespace, visibility, scope, owner self.namespace = opts[:namespace] self.visibility = opts[:visibility] || :public self.scope = opts[:scope] self.owner = opts[:owner] yield self.namespace = ns self.visibility = vis self.scope = sc self.owner = oo end # Do some post processing on a list of code objects. # Adds basic attributes to the list of objects like # the filename, line number, {CodeObjects::Base#dynamic}, # source code and {CodeObjects::Base#docstring}, # but only if they don't exist. # # @param [Array] objects # the list of objects to post-process. # # @return [CodeObjects::Base, Array] # returns whatever is passed in, for chainability. # def register(*objects) objects.flatten.each do |object| next unless object.is_a?(CodeObjects::Base) register_ensure_loaded(object) yield(object) if block_given? register_file_info(object) register_source(object) register_visibility(object) register_docstring(object) register_group(object) register_dynamic(object) register_module_function(object) end objects.size == 1 ? objects.first : objects end # Ensures that the object's namespace is loaded before attaching it # to the namespace. # # @param [CodeObjects::Base] object the object to register # @return [void] # @since 0.8.0 def register_ensure_loaded(object) begin ensure_loaded!(object.namespace) object.namespace.children << object rescue NamespaceMissingError end end # Registers the file/line of the declaration with the object # # @param [CodeObjects::Base] object the object to register # @return [void] # @since 0.8.0 def register_file_info(object, file = parser.file, line = statement.line, comments = statement.comments) object.add_file(file, line, comments) end # Registers any docstring found for the object and expands macros # # @param [CodeObjects::Base] object the object to register # @return [void] # @since 0.8.0 def register_docstring(object, docstring = statement.comments, stmt = statement) docstring = docstring.join("\n") if Array === docstring parser = Docstring.parser parser.parse(docstring || "", object, self) if object && docstring object.docstring = parser.to_docstring # Add hash_flag/line_range if stmt object.docstring.hash_flag = stmt.comments_hash_flag object.docstring.line_range = stmt.comments_range end end register_transitive_tags(object) end # Registers the object as being inside a specific group # # @param [CodeObjects::Base] object the object to register # @return [void] # @since 0.8.0 def register_group(object, group = extra_state.group) if group unless object.namespace.is_a?(Proxy) object.namespace.groups |= [group] end object.group = group end end # Registers any transitive tags from the namespace on the object # # @param [CodeObjects::Base, nil] object the object to register # @return [void] # @since 0.8.0 def register_transitive_tags(object) return unless object Tags::Library.transitive_tags.each do |tag| next if object.namespace.is_a?(Proxy) next unless object.namespace.has_tag?(tag) next if object.has_tag?(tag) object.add_tag(*object.namespace.tags(tag)) end end # @param [CodeObjects::Base] object the object to register # @return [void] # @since 0.8.0 def register_source(object, source = statement, type = parser.parser_type) return unless object.is_a?(MethodObject) object.source ||= source object.source_type = type end # Registers visibility on a method object. If the object does not # respond to setting visibility, nothing is done. # # @param [#visibility=] object the object to register # @param [Symbol] visibility the visibility to set on the object # @since 0.8.0 def register_visibility(object, visibility = self.visibility) return unless object.respond_to?(:visibility=) return if object.is_a?(NamespaceObject) object.visibility = visibility end # Registers the same method information on the module function, if # the object was defined as a module function. # # @param [CodeObjects::Base] object the possible module function object # to copy data for # @since 0.8.0 def register_module_function(object) return unless object.is_a?(MethodObject) return unless object.module_function? modobj = MethodObject.new(object.namespace, object.name) object.copy_to(modobj) modobj.visibility = :private end # Registers the object as dynamic if the object is defined inside # a method or block (owner != namespace) # # @param [CodeObjects::Base] object the object to register # @return [void] # @since 0.8.0 def register_dynamic(object) object.dynamic = true if owner != namespace end # Ensures that a specific +object+ has been parsed and loaded into the # registry. This is necessary when adding data to a namespace, for instance, # since the namespace may not have been processed yet (it can be located # in a file that has not been handled). # # Calling this method defers the handler until all other files have been # processed. If the object gets resolved, the rest of the handler continues, # otherwise an exception is raised. # # @example Adding a mixin to the String class programmatically # ensure_loaded! P('String') # # "String" is now guaranteed to be loaded # P('String').mixins << P('MyMixin') # # @param [Proxy, CodeObjects::Base] object the object to resolve. # @param [Integer] max_retries the number of times to defer the handler # before raising a +NamespaceMissingError+. # @raise [NamespaceMissingError] if the object is not resolved within # +max_retries+ attempts, this exception is raised and the handler # finishes processing. def ensure_loaded!(object, max_retries = 1) return if object.root? return object unless object.is_a?(Proxy) retries = 0 while object.is_a?(Proxy) if retries <= max_retries log.debug "Missing object #{object} in file `#{parser.file}', moving it to the back of the line." parser.parse_remaining_files else raise NamespaceMissingError, object end retries += 1 end object end # @group Macro Support # @abstract Implement this method to return the parameters in a method call # statement. It should return an empty list if the statement is not a # method call. # @return [Array] a list of argument names def call_params raise NotImplementedError end # @abstract Implement this method to return the method being called in # a method call. It should return nil if the statement is not a method # call. # @return [String] the method name being called # @return [nil] if the statement is not a method call def caller_method raise NotImplementedError end end end end yard-0.8.7.3/lib/yard/handlers/ruby/0000755000004100000410000000000012261240652017144 5ustar www-datawww-datayard-0.8.7.3/lib/yard/handlers/ruby/module_function_handler.rb0000644000004100000410000000154712261240652024367 0ustar www-datawww-data# Handles module_function calls to turn methods into public class methods. # Also creates a private instance copy of the method. class YARD::Handlers::Ruby::ModuleFunctionHandler < YARD::Handlers::Ruby::Base handles method_call(:module_function) namespace_only process do return if (ident = statement.jump(:ident)) == statement case statement.type when :var_ref, :vcall self.scope = :module when :fcall, :command statement[1].traverse do |node| case node.type when :symbol; name = node.first.source when :string_content; name = node.source else next end instance_method = MethodObject.new(namespace, name) class_method = MethodObject.new(namespace, name, :module) instance_method.copy_to(class_method) class_method.visibility = :public end end end end yard-0.8.7.3/lib/yard/handlers/ruby/dsl_handler_methods.rb0000644000004100000410000000444312261240652023500 0ustar www-datawww-datamodule YARD module Handlers module Ruby module DSLHandlerMethods include CodeObjects include Parser IGNORE_METHODS = Hash[*%w(alias alias_method autoload attr attr_accessor attr_reader attr_writer extend include public private protected private_constant).map {|n| [n, true] }.flatten] def handle_comments return if IGNORE_METHODS[caller_method] @docstring = statement.comments || "" @docstring = @docstring.join("\n") if @docstring.is_a?(Array) if @docstring =~ /^@!?macro\s+\[[^\]]*attach/ register_docstring(nil) @docstring = "" end if macro = find_attached_macro @docstring += "\n" + macro.expand([caller_method, *call_params], statement.source) elsif !statement.comments_hash_flag && !implicit_docstring? return register_docstring(nil) end # ignore DSL definitions if @method/@attribute directive is used if @docstring =~ /^@!?(method|attribute)\b/ return register_docstring(nil) end object = MethodObject.new(namespace, method_name, scope) object.signature = method_signature register(object) end def register_docstring(object, docstring = @docstring, stmt = statement) super end private def implicit_docstring? tags = %w(method attribute overload visibility scope return) tags.any? {|tag| @docstring =~ /^@!?#{tag}\b/ } end def method_name name = call_params.first || "" if name =~ /^#{CodeObjects::METHODNAMEMATCH}$/ name else raise UndocumentableError, "method, missing name" end end def method_signature "def #{method_name}" end def find_attached_macro Registry.all(:macro).each do |macro| next unless macro.method_object next unless macro.method_object.name.to_s == caller_method.to_s (namespace.inheritance_tree(true) + [P('Object')]).each do |obj| return macro if obj == macro.method_object.namespace end end nil end end end end endyard-0.8.7.3/lib/yard/handlers/ruby/mixin_handler.rb0000644000004100000410000000221112261240652022306 0ustar www-datawww-data# Handles the 'include' statement to mixin a module in the instance scope class YARD::Handlers::Ruby::MixinHandler < YARD::Handlers::Ruby::Base handles method_call(:include) namespace_only process do errors = [] statement.parameters(false).reverse.each do |mixin| begin process_mixin(mixin) rescue YARD::Parser::UndocumentableError => err errors << err.message end end if errors.size > 0 msg = errors.size == 1 ? ": #{errors[0]}" : "s: #{errors.join(", ")}" raise YARD::Parser::UndocumentableError, "mixin#{msg} for class #{namespace.path}" end end protected def process_mixin(mixin) raise YARD::Parser::UndocumentableError unless mixin.ref? raise YARD::Parser::UndocumentableError if mixin.first.type == :ident case obj = Proxy.new(namespace, mixin.source) when ConstantObject # If a constant is included, use its value as the real object obj = Proxy.new(namespace, obj.value, :module) else obj = Proxy.new(namespace, mixin.source, :module) end namespace.mixins(scope).unshift(obj) unless namespace.mixins(scope).include?(obj) end end yard-0.8.7.3/lib/yard/handlers/ruby/extend_handler.rb0000644000004100000410000000102112261240652022447 0ustar www-datawww-data# Handles 'extend' call to include modules into the class scope of another # @see MixinHandler class YARD::Handlers::Ruby::ExtendHandler < YARD::Handlers::Ruby::MixinHandler handles method_call(:extend) namespace_only def scope; :class end private def process_mixin(mixin) if mixin == s(:var_ref, s(:kw, "self")) if namespace.is_a?(ClassObject) raise UndocumentableError, "extend(self) statement on class" end namespace.mixins(scope) << namespace else super end end end yard-0.8.7.3/lib/yard/handlers/ruby/legacy/0000755000004100000410000000000012261240652020410 5ustar www-datawww-datayard-0.8.7.3/lib/yard/handlers/ruby/legacy/module_function_handler.rb0000644000004100000410000000110412261240652025620 0ustar www-datawww-data# (see Ruby::ModuleFunctionHandler) class YARD::Handlers::Ruby::Legacy::ModuleFunctionHandler < YARD::Handlers::Ruby::Legacy::Base handles /\A(module_function)(\s|\(|$)/ namespace_only process do if statement.tokens.size == 1 self.scope = :module else tokval_list(statement.tokens[2..-1], :attr).each do |name| instance_method = MethodObject.new(namespace, name) class_method = MethodObject.new(namespace, name, :module) instance_method.copy_to(class_method) class_method.visibility = :public end end end end yard-0.8.7.3/lib/yard/handlers/ruby/legacy/mixin_handler.rb0000644000004100000410000000216012261240652023555 0ustar www-datawww-data# (see Ruby::MixinHandler) class YARD::Handlers::Ruby::Legacy::MixinHandler < YARD::Handlers::Ruby::Legacy::Base handles /\Ainclude(\s|\()/ namespace_only process do errors = [] statement.tokens[1..-1].to_s.split(/\s*,\s*/).reverse.each do |mixin| mixin = mixin.strip begin process_mixin(mixin) rescue YARD::Parser::UndocumentableError => err errors << err.message end end if errors.size > 0 msg = errors.size == 1 ? ": #{errors[0]}" : "s: #{errors.join(", ")}" raise YARD::Parser::UndocumentableError, "mixin#{msg} for class #{namespace.path}" end end private def process_mixin(mixin) unless mixmatch = mixin[/\A(#{NAMESPACEMATCH})/, 1] raise YARD::Parser::UndocumentableError end case obj = Proxy.new(namespace, mixmatch) when ConstantObject # If a constant is included, use its value as the real object obj = Proxy.new(namespace, obj.value, :module) else obj = Proxy.new(namespace, mixmatch, :module) end namespace.mixins(scope).unshift(obj) unless namespace.mixins(scope).include?(obj) end end yard-0.8.7.3/lib/yard/handlers/ruby/legacy/extend_handler.rb0000644000004100000410000000070612261240652023724 0ustar www-datawww-data# (see Ruby::ExtendHandler) class YARD::Handlers::Ruby::Legacy::ExtendHandler < YARD::Handlers::Ruby::Legacy::MixinHandler handles /\Aextend(\s|\()/ namespace_only def scope; :class end private def process_mixin(mixin) if mixin == "self" if namespace.is_a?(ClassObject) raise UndocumentableError, "extend(self) statement on class" end namespace.mixins(scope) << namespace else super end end end yard-0.8.7.3/lib/yard/handlers/ruby/legacy/attribute_handler.rb0000644000004100000410000000406712261240652024444 0ustar www-datawww-data# (see Ruby::AttributeHandler) class YARD::Handlers::Ruby::Legacy::AttributeHandler < YARD::Handlers::Ruby::Legacy::Base handles /\Aattr(?:_(?:reader|writer|accessor))?(?:\s|\()/ namespace_only process do begin attr_type = statement.tokens.first.text.to_sym symbols = tokval_list statement.tokens[2..-1], :attr, TkTRUE, TkFALSE read, write = true, false rescue SyntaxError raise YARD::Parser::UndocumentableError, attr_type end # Change read/write based on attr_reader/writer/accessor case attr_type when :attr # In the case of 'attr', the second parameter (if given) isn't a symbol. write = symbols.pop if symbols.size == 2 when :attr_accessor write = true when :attr_reader # change nothing when :attr_writer read, write = false, true end # Add all attributes symbols.each do |name| namespace.attributes[scope][name] = SymbolHash[:read => nil, :write => nil] # Show their methods as well {:read => name, :write => "#{name}="}.each do |type, meth| if (type == :read ? read : write) o = MethodObject.new(namespace, meth, scope) if type == :write o.parameters = [['value', nil]] src = "def #{meth}(value)" full_src = "#{src}\n @#{name} = value\nend" doc = "Sets the attribute #{name}\n@param value the value to set the attribute #{name} to." else src = "def #{meth}" full_src = "#{src}\n @#{name}\nend" doc = "Returns the value of attribute #{name}" end o.source ||= full_src o.signature ||= src register(o) o.docstring = doc if o.docstring.blank?(false) # Regsiter the object explicitly namespace.attributes[scope][name][type] = o elsif obj = namespace.children.find {|o| o.name == meth.to_sym && o.scope == scope } # register an existing method as attribute namespace.attributes[scope][name][type] = obj end end end end endyard-0.8.7.3/lib/yard/handlers/ruby/legacy/class_handler.rb0000644000004100000410000000733512261240652023547 0ustar www-datawww-data# (see Ruby::ClassHandler) class YARD::Handlers::Ruby::Legacy::ClassHandler < YARD::Handlers::Ruby::Legacy::Base include YARD::Handlers::Ruby::StructHandlerMethods handles TkCLASS namespace_only process do if statement.tokens.to_s =~ /^class\s+(#{NAMESPACEMATCH})\s*(?:<\s*(.+)|\Z)/m classname = $1 superclass_def = $2 superclass = parse_superclass($2) classname = classname.gsub(/\s/, '') if superclass == "Struct" is_a_struct = true superclass = struct_superclass_name(superclass_def) create_struct_superclass(superclass, superclass_def) end undocsuper = superclass_def && superclass.nil? klass = register ClassObject.new(namespace, classname) do |o| o.superclass = superclass if superclass o.superclass.type = :class if o.superclass.is_a?(Proxy) end if is_a_struct parse_struct_subclass(klass, superclass_def) elsif klass create_attributes(klass, members_from_tags(klass)) end parse_block(:namespace => klass) if undocsuper raise YARD::Parser::UndocumentableError, 'superclass (class was added without superclass)' end elsif statement.tokens.to_s =~ /^class\s*<<\s*([\w\:\s]+)/ classname = $1.gsub(/\s/, '') proxy = Proxy.new(namespace, classname) # Allow constants to reference class names if ConstantObject === proxy if proxy.value =~ /\A#{NAMESPACEMATCH}\Z/ proxy = Proxy.new(namespace, proxy.value) else raise YARD::Parser::UndocumentableError, "constant class reference '#{classname}'" end end if classname == "self" parse_block(:namespace => namespace, :scope => :class) elsif classname[0,1] =~ /[A-Z]/ register ClassObject.new(namespace, classname) if Proxy === proxy parse_block(:namespace => proxy, :scope => :class) else raise YARD::Parser::UndocumentableError, "class '#{classname}'" end else raise YARD::Parser::UndocumentableError, "class: #{statement.tokens}" end end private # Extracts the parameter list from the Struct.new declaration and returns it # formatted as a list of member names. Expects the user will have used symbols # to define the struct member names # # @param [String] superstring the string declaring the superclass # @return [Array] a list of member names def extract_parameters(superstring) paramstring = superstring.match(/\A(O?Struct)\.new\((.*?)\)/)[2] paramstring.split(",").select {|x| x.strip[0,1] == ":"}.map {|x| x.strip[1..-1] } # the 1..-1 chops the leading : end def create_struct_superclass(superclass, superclass_def) return if superclass == "Struct" the_super = register ClassObject.new(P("Struct"), superclass[8..-1]) do |o| o.superclass = "Struct" end parse_struct_subclass(the_super, superclass_def) the_super end def struct_superclass_name(superclass) if match = superclass.match(/\A(Struct)\.new\((.*?)\)/) paramstring = match[2].split(",") first = paramstring.first.strip if first[0,1] =~ /['"]/ && first[-1,1] =~ /['"]/ && first !~ /\#\{/ return "Struct::#{first[1..-2]}" end end "Struct" end def parse_struct_subclass(klass, superclass_def) # Bounce if there's no parens return unless superclass_def =~ /O?Struct\.new\((.*?)\)/ members = extract_parameters(superclass_def) create_attributes(klass, members) end def parse_superclass(superclass) case superclass when /\A(#{NAMESPACEMATCH})(?:\s|\Z)/, /\A(Struct|OStruct)\.new/, /\ADelegateClass\((.+?)\)\s*\Z/, /\A(#{NAMESPACEMATCH})\(/ $1 when "self" namespace.path end end endyard-0.8.7.3/lib/yard/handlers/ruby/legacy/visibility_handler.rb0000644000004100000410000000074012261240652024622 0ustar www-datawww-data# (see Ruby::VisibilityHandler) class YARD::Handlers::Ruby::Legacy::VisibilityHandler < YARD::Handlers::Ruby::Legacy::Base handles /\A(protected|private|public)(\s|\(|$)/ namespace_only process do vis = statement.tokens.first.text if statement.tokens.size == 1 self.visibility = vis else tokval_list(statement.tokens[2..-1], :attr).each do |name| MethodObject.new(namespace, name, scope) {|o| o.visibility = vis } end end end endyard-0.8.7.3/lib/yard/handlers/ruby/legacy/class_condition_handler.rb0000644000004100000410000000435712261240652025616 0ustar www-datawww-data# (see Ruby::ClassConditionHandler) # @since 0.5.4 class YARD::Handlers::Ruby::Legacy::ClassConditionHandler < YARD::Handlers::Ruby::Legacy::Base namespace_only handles TkIF, TkELSIF, TkUNLESS process do condition = parse_condition if condition == nil # Parse both blocks if we're unsure of the condition parse_then_block parse_else_block elsif condition parse_then_block else parse_else_block end end protected # Parses the condition part of the if/unless statement # # @return [true, false, nil] true if the condition can be definitely # parsed to true, false if not, and nil if the condition cannot be # parsed with certainty (it's dynamic) # @since 0.5.5 def parse_condition condition = nil # Right now we can handle very simple unary conditions like: # if true # if false # if 0 # if 100 (not 0) # if defined? SOME_CONSTANT # # The last case will do a lookup in the registry and then one # in the Ruby world (using eval). case statement.tokens[1..-1].to_s.strip when /^(\d+)$/ condition = $1 != "0" when /^defined\?\s*\(?(.+?)\)?$/ # defined? keyword used, let's see if we can look up the name # in the registry, then we'll try using Ruby's powers. eval() is not # *too* dangerous here since code is not actually executed. name = $1 obj = YARD::Registry.resolve(namespace, name, true) begin condition = true if obj || Object.instance_eval("defined? #{name}") rescue SyntaxError, NameError condition = false end when "true" condition = true when "false" condition = false end if TkUNLESS === statement.tokens.first condition = !condition if condition != nil end condition end # @since 0.5.5 def parse_then_block parse_block(:visibility => visibility) end # @since 0.5.5 def parse_else_block return unless statement.block stmtlist = YARD::Parser::Ruby::Legacy::StatementList stmtlist.new(statement.block).each do |stmt| if TkELSE === stmt.tokens.first push_state(:visibility => visibility) do parser.process(stmtlist.new(stmt.block)) end end end end endyard-0.8.7.3/lib/yard/handlers/ruby/legacy/method_handler.rb0000644000004100000410000000544112261240652023716 0ustar www-datawww-data# (see Ruby::MethodHandler) class YARD::Handlers::Ruby::Legacy::MethodHandler < YARD::Handlers::Ruby::Legacy::Base handles TkDEF process do nobj = namespace mscope = scope if statement.tokens.to_s =~ /^def\s+(#{METHODMATCH})(?:(?:\s+|\s*\()(.*)(?:\)\s*$)?)?/m meth, args = $1, $2 meth.gsub!(/\s+/,'') args = tokval_list(YARD::Parser::Ruby::Legacy::TokenList.new(args), :all) args.map! do |a| k, v, r = *a.split(/(:)|=/, 2) if r k += v v = r end [k.strip, (v ? v.strip : nil)] end if args else raise YARD::Parser::UndocumentableError, "method: invalid name" end # Class method if prefixed by self(::|.) or Module(::|.) if meth =~ /(?:#{NSEPQ}|#{CSEPQ})([^#{NSEP}#{CSEPQ}]+)$/ mscope, meth, prefix = :class, $1, $` if prefix =~ /^[a-z]/ && prefix != "self" raise YARD::Parser::UndocumentableError, 'method defined on object instance' end nobj = P(namespace, prefix) unless prefix == "self" end nobj = P(namespace, nobj.value) while nobj.type == :constant obj = register MethodObject.new(nobj, meth, mscope) do |o| o.explicit = true o.parameters = args end # delete any aliases referencing old method nobj.aliases.each do |aobj, name| next unless name == obj.name nobj.aliases.delete(aobj) end if nobj.is_a?(NamespaceObject) if mscope == :instance && meth == "initialize" unless obj.has_tag?(:return) obj.add_tag(YARD::Tags::Tag.new(:return, "a new instance of #{namespace.name}", namespace.name.to_s)) end elsif mscope == :class && obj.docstring.blank? && %w(inherited included extended method_added method_removed method_undefined).include?(meth) obj.add_tag(YARD::Tags::Tag.new(:private, nil)) elsif meth.to_s =~ /\?$/ if obj.tag(:return) && (obj.tag(:return).types || []).empty? obj.tag(:return).types = ['Boolean'] elsif obj.tag(:return).nil? unless obj.tags(:overload).any? {|overload| overload.tag(:return) } obj.add_tag(YARD::Tags::Tag.new(:return, "", "Boolean")) end end end if obj.has_tag?(:option) # create the options parameter if its missing obj.tags(:option).each do |option| expected_param = option.name unless obj.tags(:param).find {|x| x.name == expected_param } new_tag = YARD::Tags::Tag.new(:param, "a customizable set of options", "Hash", expected_param) obj.add_tag(new_tag) end end end if info = obj.attr_info if meth.to_s =~ /=$/ # writer info[:write] = obj if info[:read] else info[:read] = obj if info[:write] end end parse_block(:owner => obj) # mainly for yield/exceptions end end yard-0.8.7.3/lib/yard/handlers/ruby/legacy/module_handler.rb0000644000004100000410000000052112261240652023715 0ustar www-datawww-data# (see Ruby::ModuleHandler) class YARD::Handlers::Ruby::Legacy::ModuleHandler < YARD::Handlers::Ruby::Legacy::Base handles TkMODULE namespace_only process do modname = statement.tokens.to_s[/^module\s+(#{NAMESPACEMATCH})/, 1] mod = register ModuleObject.new(namespace, modname) parse_block(:namespace => mod) end endyard-0.8.7.3/lib/yard/handlers/ruby/legacy/class_variable_handler.rb0000644000004100000410000000063612261240652025411 0ustar www-datawww-data# (see Ruby::ClassVariableHandler) class YARD::Handlers::Ruby::Legacy::ClassVariableHandler < YARD::Handlers::Ruby::Legacy::Base HANDLER_MATCH = /\A@@\w+\s*=\s*/m handles HANDLER_MATCH namespace_only process do name, value = *statement.tokens.to_s.split(/\s*=\s*/, 2) register ClassVariableObject.new(namespace, name) do |o| o.source = statement o.value = value.strip end end endyard-0.8.7.3/lib/yard/handlers/ruby/legacy/yield_handler.rb0000644000004100000410000000200012261240652023530 0ustar www-datawww-data# (see Ruby::YieldHandler) class YARD::Handlers::Ruby::Legacy::YieldHandler < YARD::Handlers::Ruby::Legacy::Base handles TkYIELD process do return unless owner.is_a?(MethodObject) # Only methods yield return if owner.has_tag? :yield # Don't override yield tags return if owner.has_tag? :yieldparam # Same thing. yieldtag = YARD::Tags::Tag.new(:yield, "", []) tokval_list(statement.tokens[2..-1], Token).each do |item| item = item.inspect unless item.is_a?(String) if item == "self" yieldtag.types << '_self' owner.add_tag YARD::Tags::Tag.new(:yieldparam, "the object that the method was called on", owner.namespace.path, '_self') elsif item == "super" yieldtag.types << '_super' owner.add_tag YARD::Tags::Tag.new(:yieldparam, "the result of the method from the superclass", nil, '_super') else yieldtag.types << item end end owner.add_tag(yieldtag) unless yieldtag.types.empty? end end yard-0.8.7.3/lib/yard/handlers/ruby/legacy/alias_handler.rb0000644000004100000410000000255212261240652023527 0ustar www-datawww-data# (see Ruby::AliasHandler) class YARD::Handlers::Ruby::Legacy::AliasHandler < YARD::Handlers::Ruby::Legacy::Base handles /\Aalias(_method)?(\s|\()/ namespace_only process do if TkALIAS === statement.tokens.first tokens = statement.tokens[2..-1].to_s.split(/\s+/) names = [tokens[0], tokens[1]].map {|t| t.gsub(/^:(['"])?(.+?)\1?$|^(:)(.+)/, '\2') } else names = tokval_list(statement.tokens[2..-1], :attr) end raise YARD::Parser::UndocumentableError, statement.tokens.first.text if names.size != 2 names = names.map {|n| Symbol === n ? n.to_s.gsub('"', '') : n } new_meth, old_meth = names[0].to_sym, names[1].to_sym old_obj = namespace.child(:name => old_meth, :scope => scope) new_obj = register MethodObject.new(namespace, new_meth, scope) do |o| o.add_file(parser.file, statement.tokens.first.line_no, statement.comments) end if old_obj new_obj.signature = old_obj.signature new_obj.source = old_obj.source new_obj.docstring = old_obj.docstring + YARD::Docstring.new(statement.comments) new_obj.docstring.line_range = statement.comments_range new_obj.docstring.hash_flag = statement.comments_hash_flag new_obj.docstring.object = new_obj else new_obj.signature = "def #{new_meth}" # this is all we know. end namespace.aliases[new_obj] = old_meth end endyard-0.8.7.3/lib/yard/handlers/ruby/legacy/dsl_handler.rb0000644000004100000410000000051312261240652023213 0ustar www-datawww-datamodule YARD module Handlers module Ruby module Legacy # (see Ruby::DSLHandler) class DSLHandler < Base include CodeObjects include DSLHandlerMethods handles TkIDENTIFIER namespace_only process { handle_comments } end end end end end yard-0.8.7.3/lib/yard/handlers/ruby/legacy/exception_handler.rb0000644000004100000410000000073512261240652024435 0ustar www-datawww-data# (see Ruby::ExceptionHandler) class YARD::Handlers::Ruby::Legacy::ExceptionHandler < YARD::Handlers::Ruby::Legacy::Base handles /\Araise(\s|\(|\Z)/ process do return unless owner.is_a?(MethodObject) # Only methods yield return if owner.has_tag?(:raise) klass = statement.tokens.to_s[/^raise[\(\s]*(#{NAMESPACEMATCH})\s*(?:\)|,|\s(?:if|unless|until)|;|(?:(?:\.|\:\:)\s*)?new|$)/, 1] owner.add_tag YARD::Tags::Tag.new(:raise, '', klass) if klass end end yard-0.8.7.3/lib/yard/handlers/ruby/legacy/constant_handler.rb0000644000004100000410000000156412261240652024271 0ustar www-datawww-data# (see Ruby::ConstantHandler) class YARD::Handlers::Ruby::Legacy::ConstantHandler < YARD::Handlers::Ruby::Legacy::Base include YARD::Handlers::Ruby::StructHandlerMethods HANDLER_MATCH = /\A[A-Z]\w*\s*=[^=]\s*/m handles HANDLER_MATCH namespace_only process do name, value = *statement.tokens.to_s.split(/\s*=\s*/, 2) if value =~ /\A\s*Struct.new(?:\s*\(?|\b)/ process_structclass(name, $') else register ConstantObject.new(namespace, name) {|o| o.source = statement; o.value = value.strip } end end private def process_structclass(classname, parameters) klass = create_class(classname, P(:Struct)) create_attributes(klass, extract_parameters(parameters)) end def extract_parameters(parameters) members = tokval_list(YARD::Parser::Ruby::Legacy::TokenList.new(parameters), TkSYMBOL) members.map {|m| m.to_s } end end yard-0.8.7.3/lib/yard/handlers/ruby/legacy/comment_handler.rb0000644000004100000410000000031612261240652024074 0ustar www-datawww-data# (see Ruby::CommentHandler) class YARD::Handlers::Ruby::Legacy::CommentHandler < YARD::Handlers::Ruby::Legacy::Base handles TkCOMMENT namespace_only process do register_docstring(nil) end end yard-0.8.7.3/lib/yard/handlers/ruby/legacy/base.rb0000644000004100000410000002245212261240652021654 0ustar www-datawww-datamodule YARD module Handlers module Ruby::Legacy # This is the base handler for the legacy parser. To implement a legacy # handler, subclass this class. # # @abstract (see Ruby::Base) class Base < Handlers::Base # For tokens like TkDEF, TkCLASS, etc. include YARD::Parser::Ruby::Legacy::RubyToken # @return [Boolean] whether or not a {Parser::Ruby::Legacy::Statement} object should be handled # by this handler. def self.handles?(stmt) handlers.any? do |a_handler| case a_handler when String stmt.tokens.first.text == a_handler when Regexp stmt.tokens.to_s =~ a_handler else a_handler == stmt.tokens.first.class end end end # Parses a statement's block with a set of state values. If the # statement has no block, nothing happens. A description of state # values can be found at {Handlers::Base#push_state} # # @param [Hash] opts State options # @option opts (see Handlers::Base#push_state) # @see Handlers::Base#push_state #push_state def parse_block(opts = {}) push_state(opts) do if statement.block blk = Parser::Ruby::Legacy::StatementList.new(statement.block) parser.process(blk) end end end def call_params if statement.tokens.first.is_a?(TkDEF) extract_method_details.last.map {|param| param.first } else tokens = statement.tokens[1..-1] tokval_list(tokens, :attr, :identifier, TkId).map do |value| value.to_s end end end def caller_method if statement.tokens.first.is_a?(TkIDENTIFIER) statement.tokens.first.text elsif statement.tokens.first.is_a?(TkDEF) extract_method_details.first else nil end end private # Extracts method information for macro expansion only # # @todo This is a duplicate implementation of {MethodHandler}. Refactor. # @return [Array>>] the method name followed by method # arguments (name and optional value) def extract_method_details if statement.tokens.to_s =~ /^def\s+(#{METHODMATCH})(?:(?:\s+|\s*\()(.*)(?:\)\s*$)?)?/m meth, args = $1, $2 meth.gsub!(/\s+/,'') args = tokval_list(Parser::Ruby::Legacy::TokenList.new(args), :all) args.map! {|a| k, v = *a.split('=', 2); [k.strip, (v ? v.strip : nil)] } if args if meth =~ /(?:#{NSEPQ}|#{CSEPQ})([^#{NSEP}#{CSEPQ}]+)$/ meth = $` end return meth, args end end # The string value of a token. For example, the return value for the symbol :sym # would be :sym. The return value for a string +"foo #{ bar}"+ would be the literal # +"foo #{ bar}"+ without any interpolation. The return value of the identifier # 'test' would be the same value: 'test'. Here is a list of common types and # their return values: # # @example # tokval(TokenList.new('"foo"').first) => "foo" # tokval(TokenList.new(':foo').first) => :foo # tokval(TokenList.new('CONSTANT').first, RubyToken::TkId) => "CONSTANT" # tokval(TokenList.new('identifier').first, RubyToken::TkId) => "identifier" # tokval(TokenList.new('3.25').first) => 3.25 # tokval(TokenList.new('/xyz/i').first) => /xyz/i # # @param [Token] token The token of the class # # @param [Array>, Symbol] accepted_types # The allowed token types that this token can be. Defaults to [{TkVal}]. # A list of types would be, for example, [+TkSTRING+, +TkSYMBOL+], to return # the token's value if it is either of those types. If +TkVal+ is accepted, # +TkNode+ is also accepted. # # Certain symbol keys are allowed to specify multiple types in one fell swoop. # These symbols are: # :string => +TkSTRING+, +TkDSTRING+, +TkDXSTRING+ and +TkXSTRING+ # :attr => +TkSYMBOL+ and +TkSTRING+ # :identifier => +TkIDENTIFIER, +TkFID+ and +TkGVAR+. # :number => +TkFLOAT+, +TkINTEGER+ # # @return [Object] if the token is one of the accepted types, in its real value form. # It should be noted that identifiers and constants are kept in String form. # @return [nil] if the token is not any of the specified accepted types def tokval(token, *accepted_types) accepted_types = [TkVal] if accepted_types.empty? accepted_types.push(TkNode) if accepted_types.include? TkVal if accepted_types.include?(:attr) accepted_types.push(TkSTRING, TkSYMBOL) end if accepted_types.include?(:string) accepted_types.push(TkSTRING, TkDSTRING, TkXSTRING, TkDXSTRING) end if accepted_types.include?(:identifier) accepted_types.push(TkIDENTIFIER, TkFID, TkGVAR) end if accepted_types.include?(:number) accepted_types.push(TkFLOAT, TkINTEGER) end return unless accepted_types.any? {|t| t === token } case token when TkSTRING, TkDSTRING, TkXSTRING, TkDXSTRING token.text[1..-2] when TkSYMBOL token.text[1..-1].to_sym when TkFLOAT token.text.to_f when TkINTEGER token.text.to_i when TkREGEXP token.text =~ /\A\/(.+)\/([^\/])\Z/ Regexp.new($1, $2) when TkTRUE true when TkFALSE false when TkNIL nil else token.text end end # Returns a list of symbols or string values from a statement. # The list must be a valid comma delimited list, and values # will only be returned to the end of the list only. # # Example: # attr_accessor :a, 'b', :c, :d => ['a', 'b', 'c', 'd'] # attr_accessor 'a', UNACCEPTED_TYPE, 'c' => ['a', 'c'] # # The tokval list of a {Parser::Ruby::Legacy::TokenList} of the above # code would be the {#tokval} value of :a, 'b', # :c and :d. # # It should also be noted that this function stops immediately at # any ruby keyword encountered: # "attr_accessor :a, :b, :c if x == 5" => ['a', 'b', 'c'] # # @param [TokenList] tokenlist The list of tokens to process. # @param [Array>] accepted_types passed to {#tokval} # @return [Array] the list of tokvalues in the list. # @return [Array] if there are no symbols or Strings in the list # @see #tokval def tokval_list(tokenlist, *accepted_types) return [] unless tokenlist out = [[]] parencount, beforeparen = 0, 0 needcomma = false seen_comma = true tokenlist.each do |token| tokval = accepted_types == [:all] ? token.text : tokval(token, *accepted_types) parencond = !out.last.empty? && tokval != nil #puts "#{seen_comma.inspect} #{parencount} #{token.class.class_name} #{out.inspect}" case token when TkCOMMA if parencount == 0 out << [] unless out.last.empty? needcomma = false seen_comma = true else out.last << token.text if parencond end when TkLPAREN if seen_comma beforeparen += 1 else parencount += 1 out.last << token.text if parencond end when TkRPAREN if beforeparen > 0 beforeparen -= 1 else out.last << token.text if parencount > 0 && tokval != nil parencount -= 1 end when TkLBRACE, TkLBRACK, TkDO parencount += 1 out.last << token.text if tokval != nil when TkRBRACE, TkRBRACK, TkEND out.last << token.text if tokval != nil parencount -= 1 else break if TkKW === token && ![TkTRUE, TkFALSE, TkSUPER, TkSELF, TkNIL].include?(token.class) seen_comma = false unless TkWhitespace === token if parencount == 0 next if needcomma next if TkWhitespace === token if tokval != nil out.last << tokval else out.last.clear needcomma = true end elsif parencond needcomma = true out.last << token.text end end if beforeparen == 0 && parencount < 0 break end end # Flatten any single element lists out.map {|e| e.empty? ? nil : (e.size == 1 ? e.pop : e.flatten.join) }.compact end end end end endyard-0.8.7.3/lib/yard/handlers/ruby/legacy/private_constant_handler.rb0000644000004100000410000000112212261240652026011 0ustar www-datawww-data# (see Ruby::PrivateConstantHandler) class YARD::Handlers::Ruby::Legacy::PrivateConstantHandler < YARD::Handlers::Ruby::Legacy::Base handles /\Aprivate_constant(\s|\(|$)/ namespace_only process do tokval_list(statement.tokens[2..-1], :attr, TkCONSTANT).each do |name| privatize_constant name end end private def privatize_constant(name) const = Proxy.new(namespace, name) ensure_loaded!(const) const.visibility = :private rescue NamespaceMissingError raise UndocumentableError, "private visibility set on unrecognized constant: #{name}" end end yard-0.8.7.3/lib/yard/handlers/ruby/method_condition_handler.rb0000644000004100000410000000034512261240652024516 0ustar www-datawww-data# Handles a conditional inside a method class YARD::Handlers::Ruby::MethodConditionHandler < YARD::Handlers::Ruby::Base handles :if_mod, :unless_mod process do parse_block(statement.then_block, :owner => owner) end endyard-0.8.7.3/lib/yard/handlers/ruby/struct_handler_methods.rb0000644000004100000410000001524212261240652024241 0ustar www-datawww-data# Helper methods to parse @attr_* tags on a class. # # @deprecated The use of +@attr+ tags are deprecated since 0.8.0 in favour of # the +@!attribute+ directive. This module should not be relied on. # @since 0.5.6 module YARD::Handlers::Ruby::StructHandlerMethods include YARD::CodeObjects # Extracts the user's defined @member tag for a given class and its member. Returns # nil if the user did not define a @member tag for this struct entry. # # @param [ClassObject] klass the class whose tags we're searching # @param [String] member the name of the struct member we need # @param [Symbol] type reader method, or writer method? # @return [Tags::Tag, nil] the tag matching the request, or nil if not found def member_tag_for_member(klass, member, type = :read) specific_tag = type == :read ? :attr_reader : :attr_writer (klass.tags(specific_tag) + klass.tags(:attr)).find {|tag| tag.name == member} end # Retrieves all members defined in @attr* tags # # @param [ClassObject] klass the class with the attributes # @return [Array] the list of members defined as attributes on the class def members_from_tags(klass) tags = klass.tags(:attr) + klass.tags(:attr_reader) + klass.tags(:attr_writer) tags.map {|t| t.name }.uniq end # Determines whether to create an attribute method based on the class's # tags. # # @param [ClassObject] klass the class whose tags we're searching # @param [String] member the name of the struct member we need # @param [Symbol] type (:read) reader method, or writer method? # @return [Boolean] should the attribute be created? def create_member_method?(klass, member, type = :read) return true if (klass.tags(:attr) + klass.tags(:attr_reader) + klass.tags(:attr_writer)).empty? return true if member_tag_for_member(klass, member, type) return !member_tag_for_member(klass, member, :write) if type == :read return !member_tag_for_member(klass, member, :read) end # Gets the return type for the member in a nicely formatted string. Used # to be injected into auto-generated docstrings. # # @param [Tags::Tag] member_tag the tag object to check for types # @return [String] the user-declared type of the struct member, or [Object] if # the user did not define a type for this member. def return_type_from_tag(member_tag) (member_tag && member_tag.types) ? member_tag.types : "Object" end # Creates the auto-generated docstring for the getter method of a struct's # member. This is used so the generated documentation will look just like that # of an attribute defined using attr_accessor. # # @param [ClassObject] klass the class whose members we're working with # @param [String] member the name of the member we're generating documentation for # @return [String] a docstring to be attached to the getter method for this member def add_reader_tags(klass, new_method, member) member_tag = member_tag_for_member(klass, member, :read) return_type = return_type_from_tag(member_tag) getter_doc_text = member_tag ? member_tag.text : "Returns the value of attribute #{member}" new_method.docstring.replace(getter_doc_text) new_method.add_tag YARD::Tags::Tag.new(:return, "the current value of #{member}", return_type) end # Creates the auto-generated docstring for the setter method of a struct's # member. This is used so the generated documentation will look just like that # of an attribute defined using attr_accessor. # # @param [ClassObject] klass the class whose members we're working with # @param [String] member the name of the member we're generating documentation for # @return [String] a docstring to be attached to the setter method for this member def add_writer_tags(klass, new_method, member) member_tag = member_tag_for_member(klass, member, :write) return_type = return_type_from_tag(member_tag) setter_doc_text = member_tag ? member_tag.text : "Sets the attribute #{member}" new_method.docstring.replace(setter_doc_text) new_method.add_tag YARD::Tags::Tag.new(:param, "the value to set the attribute #{member} to.", return_type, "value") new_method.add_tag YARD::Tags::Tag.new(:return, "the newly set value", return_type) end # Creates and registers a class object with the given name and superclass name. # Returns it for further use. # # @param [String] classname the name of the class # @param [String] superclass the name of the superclass # @return [ClassObject] the class object for further processing/method attaching def create_class(classname, superclass) register ClassObject.new(namespace, classname) do |o| o.superclass = superclass if superclass o.superclass.type = :class if o.superclass.is_a?(Proxy) end end # Creates the setter (writer) method and attaches it to the class as an attribute. # Also sets up the docstring to prettify the documentation output. # # @param [ClassObject] klass the class to attach the method to # @param [String] member the name of the member we're generating a method for def create_writer(klass, member) # We want to convert these members into attributes just like # as if they were declared using attr_accessor. new_meth = register MethodObject.new(klass, "#{member}=", :instance) do |o| o.parameters = [['value', nil]] o.signature ||= "def #{member}=(value)" o.source ||= "#{o.signature}\n @#{member} = value\nend" end add_writer_tags(klass, new_meth, member) klass.attributes[:instance][member][:write] = new_meth end # Creates the getter (reader) method and attaches it to the class as an attribute. # Also sets up the docstring to prettify the documentation output. # # @param [ClassObject] klass the class to attach the method to # @param [String] member the name of the member we're generating a method for def create_reader(klass, member) new_meth = register MethodObject.new(klass, member, :instance) do |o| o.signature ||= "def #{member}" o.source ||= "#{o.signature}\n @#{member}\nend" end add_reader_tags(klass, new_meth, member) klass.attributes[:instance][member][:read] = new_meth end # Creates the given member methods and attaches them to the given ClassObject. # # @param [ClassObject] klass the class to generate attributes for # @param [Array] members a list of member names def create_attributes(klass, members) # For each parameter, add reader and writers members.each do |member| klass.attributes[:instance][member] = SymbolHash[:read => nil, :write => nil] create_writer klass, member if create_member_method?(klass, member, :write) create_reader klass, member if create_member_method?(klass, member, :read) end end end yard-0.8.7.3/lib/yard/handlers/ruby/attribute_handler.rb0000644000004100000410000000536312261240652023200 0ustar www-datawww-data# Handles +attr_*+ statements in modules/classes class YARD::Handlers::Ruby::AttributeHandler < YARD::Handlers::Ruby::Base handles method_call(:attr) handles method_call(:attr_reader) handles method_call(:attr_writer) handles method_call(:attr_accessor) namespace_only process do return if statement.type == :var_ref || statement.type == :vcall read, write = true, false params = statement.parameters(false).dup # Change read/write based on attr_reader/writer/accessor case statement.method_name(true) when :attr # In the case of 'attr', the second parameter (if given) isn't a symbol. if params.size == 2 write = true if params.pop == s(:var_ref, s(:kw, "true")) end when :attr_accessor write = true when :attr_reader # change nothing when :attr_writer read, write = false, true end # Add all attributes validated_attribute_names(params).each do |name| namespace.attributes[scope][name] ||= SymbolHash[:read => nil, :write => nil] # Show their methods as well {:read => name, :write => "#{name}="}.each do |type, meth| if (type == :read ? read : write) o = MethodObject.new(namespace, meth, scope) if type == :write o.parameters = [['value', nil]] src = "def #{meth}(value)" full_src = "#{src}\n @#{name} = value\nend" doc = "Sets the attribute #{name}\n@param value the value to set the attribute #{name} to." else src = "def #{meth}" full_src = "#{src}\n @#{name}\nend" doc = "Returns the value of attribute #{name}" end o.source ||= full_src o.signature ||= src register(o) o.docstring = doc if o.docstring.blank?(false) # Regsiter the object explicitly namespace.attributes[scope][name][type] = o elsif obj = namespace.children.find {|o| o.name == meth.to_sym && o.scope == scope } # register an existing method as attribute namespace.attributes[scope][name][type] = obj end end end end protected # Strips out any non-essential arguments from the attr statement. # # @param [Array] params a list of the parameters # in the attr call. # @return [Array] the validated attribute names # @raise [Parser::UndocumentableError] if the arguments are not valid. def validated_attribute_names(params) params.map do |obj| case obj.type when :symbol_literal obj.jump(:ident, :op, :kw, :const).source when :string_literal obj.jump(:string_content).source else raise YARD::Parser::UndocumentableError, obj.source end end end endyard-0.8.7.3/lib/yard/handlers/ruby/class_handler.rb0000644000004100000410000001016512261240652022276 0ustar www-datawww-data# Handles class declarations class YARD::Handlers::Ruby::ClassHandler < YARD::Handlers::Ruby::Base include YARD::Handlers::Ruby::StructHandlerMethods handles :class, :sclass namespace_only process do classname = statement[0].source.gsub(/\s/, '') if statement.type == :class superclass = parse_superclass(statement[1]) if superclass == "Struct" is_a_struct = true superclass = struct_superclass_name(statement[1]) # refine the superclass if possible create_struct_superclass(superclass, statement[1]) end undocsuper = statement[1] && superclass.nil? klass = register ClassObject.new(namespace, classname) do |o| o.superclass = superclass if superclass o.superclass.type = :class if o.superclass.is_a?(Proxy) end if is_a_struct parse_struct_superclass(klass, statement[1]) elsif klass create_attributes(klass, members_from_tags(klass)) end parse_block(statement[2], :namespace => klass) if undocsuper raise YARD::Parser::UndocumentableError, 'superclass (class was added without superclass)' end elsif statement.type == :sclass if statement[0] == s(:var_ref, s(:kw, "self")) parse_block(statement[1], :namespace => namespace, :scope => :class) else proxy = Proxy.new(namespace, classname) # Allow constants to reference class names if ConstantObject === proxy if proxy.value =~ /\A#{NAMESPACEMATCH}\Z/ proxy = Proxy.new(namespace, proxy.value) else raise YARD::Parser::UndocumentableError, "constant class reference '#{classname}'" end end if classname[0,1] =~ /[A-Z]/ register ClassObject.new(namespace, classname) if Proxy === proxy parse_block(statement[1], :namespace => proxy, :scope => :class) else raise YARD::Parser::UndocumentableError, "class '#{classname}'" end end else sig_end = (statement[1] ? statement[1].source_end : statement[0].source_end) - statement.source_start raise YARD::Parser::UndocumentableError, "class: #{statement.source[0..sig_end]}" end end private # Extract the parameters from the Struct.new AST node, returning them as a list # of strings # # @param [MethodCallNode] superclass the AST node for the Struct.new call # @return [Array] the member names to generate methods for def extract_parameters(superclass) members = superclass.parameters.select {|x| x && x.type == :symbol_literal} members.map! {|x| x.source.strip[1..-1]} members end def create_struct_superclass(superclass, superclass_def) return if superclass == "Struct" the_super = register ClassObject.new(P("Struct"), superclass[8..-1]) do |o| o.superclass = "Struct" end parse_struct_superclass(the_super, superclass_def) the_super end def struct_superclass_name(superclass) if superclass.call? first = superclass.parameters.first if first.type == :string_literal && first[0].type == :string_content && first[0].size == 1 return "Struct::#{first[0][0][0]}" end end "Struct" end def parse_struct_superclass(klass, superclass) return unless superclass.call? && superclass.parameters members = extract_parameters(superclass) create_attributes(klass, members) end def parse_superclass(superclass) return nil unless superclass case superclass.type when :var_ref return namespace.path if superclass.first == s(:kw, "self") return superclass.source if superclass.first.type == :const when :const, :const_ref, :const_path_ref, :top_const_ref return superclass.source when :fcall, :command methname = superclass.method_name.source if methname == "DelegateClass" return superclass.parameters.first.source elsif superclass.method_name.type == :const return methname end when :call, :command_call cname = superclass.namespace.source if cname =~ /^O?Struct$/ && superclass.method_name(true) == :new return cname end end nil end endyard-0.8.7.3/lib/yard/handlers/ruby/visibility_handler.rb0000644000004100000410000000134312261240652023356 0ustar www-datawww-data# Handles 'private', 'protected', and 'public' calls. class YARD::Handlers::Ruby::VisibilityHandler < YARD::Handlers::Ruby::Base handles method_call(:private) handles method_call(:protected) handles method_call(:public) namespace_only process do return if (ident = statement.jump(:ident)) == statement case statement.type when :var_ref, :vcall self.visibility = ident.first.to_sym when :fcall, :command statement[1].traverse do |node| case node.type when :symbol; source = node.first.source when :string_content; source = node.source else next end MethodObject.new(namespace, source, scope) {|o| o.visibility = ident.first } end end end endyard-0.8.7.3/lib/yard/handlers/ruby/class_condition_handler.rb0000644000004100000410000000456512261240652024353 0ustar www-datawww-data# Matches if/unless conditions inside classes and attempts to process only # one branch (by evaluating the condition if possible). # # @example A simple class conditional # class Foo # if 0 # # This method is ignored # def xyz; end # end # end class YARD::Handlers::Ruby::ClassConditionHandler < YARD::Handlers::Ruby::Base handles meta_type(:condition) namespace_only process do condition = parse_condition if condition == nil # Parse both blocks if we're unsure of the condition parse_then_block parse_else_block elsif condition parse_then_block else parse_else_block end end protected # Parses the condition part of the if/unless statement # # @return [true, false, nil] true if the condition can be definitely # parsed to true, false if not, and nil if the condition cannot be # parsed with certainty (it's dynamic) def parse_condition condition = nil # Right now we can handle very simple unary conditions like: # if true # if false # if 0 # if 100 (not 0) # if defined? SOME_CONSTANT # # The last case will do a lookup in the registry and then one # in the Ruby world (using eval). case statement.condition.type when :int condition = statement.condition[0] != "0" when :defined # defined? keyword used, let's see if we can look up the name # in the registry, then we'll try using Ruby's powers. eval() is not # *too* dangerous here since code is not actually executed. name = statement.condition[0].source obj = YARD::Registry.resolve(namespace, name, true) begin condition = true if obj || Object.instance_eval("defined? #{name}") rescue SyntaxError, NameError condition = false end when :var_ref var = statement.condition[0] if var == s(:kw, "true") condition = true elsif var == s(:kw, "false") condition = false end end # Invert an unless condition if statement.type == :unless || statement.type == :unless_mod condition = !condition if condition != nil end condition end def parse_then_block parse_block(statement.then_block, :visibility => visibility) end def parse_else_block if statement.else_block parse_block(statement.else_block, :visibility => visibility) end end endyard-0.8.7.3/lib/yard/handlers/ruby/method_handler.rb0000644000004100000410000000613012261240652022446 0ustar www-datawww-data# Handles a method definition class YARD::Handlers::Ruby::MethodHandler < YARD::Handlers::Ruby::Base handles :def, :defs process do meth = statement.method_name(true).to_s args = format_args blk = statement.block nobj = namespace mscope = scope if statement.type == :defs if statement[0][0].type == :ident raise YARD::Parser::UndocumentableError, 'method defined on object instance' end nobj = P(namespace, statement[0].source) if statement[0][0].type == :const mscope = :class end nobj = P(namespace, nobj.value) while nobj.type == :constant obj = register MethodObject.new(nobj, meth, mscope) do |o| o.signature = method_signature o.explicit = true o.parameters = args end # delete any aliases referencing old method nobj.aliases.each do |aobj, name| next unless name == obj.name nobj.aliases.delete(aobj) end if nobj.is_a?(NamespaceObject) if obj.constructor? unless obj.has_tag?(:return) obj.add_tag(YARD::Tags::Tag.new(:return, "a new instance of #{namespace.name}", namespace.name.to_s)) end elsif mscope == :class && obj.docstring.blank? && %w(inherited included extended method_added method_removed method_undefined).include?(meth) obj.add_tag(YARD::Tags::Tag.new(:private, nil)) elsif meth.to_s =~ /\?$/ if obj.tag(:return) && (obj.tag(:return).types || []).empty? obj.tag(:return).types = ['Boolean'] elsif obj.tag(:return).nil? unless obj.tags(:overload).any? {|overload| overload.tag(:return) } obj.add_tag(YARD::Tags::Tag.new(:return, "", "Boolean")) end end end if obj.has_tag?(:option) # create the options parameter if its missing obj.tags(:option).each do |option| expected_param = option.name unless obj.tags(:param).find {|x| x.name == expected_param } new_tag = YARD::Tags::Tag.new(:param, "a customizable set of options", "Hash", expected_param) obj.add_tag(new_tag) end end end if info = obj.attr_info if meth.to_s =~ /=$/ # writer info[:write] = obj if info[:read] else info[:read] = obj if info[:write] end end parse_block(blk, :owner => obj) # mainly for yield/exceptions end def format_args args = statement.parameters params = [] params += args.required_params.map {|a| [a.source, nil] } if args.required_params params += args.optional_params.map {|a| [a[0].source, a[1].source] } if args.optional_params params << ["*" + args.splat_param.source, nil] if args.splat_param params << ["**" + args.keyword_param.source, nil] if args.keyword_param params += args.required_end_params.map {|a| [a.source, nil] } if args.required_end_params params << ["&" + args.block_param.source, nil] if args.block_param params end def method_signature method_name = statement.method_name(true) if statement.parameters.any? {|e| e } "def #{method_name}(#{statement.parameters.source})" else "def #{method_name}" end end end yard-0.8.7.3/lib/yard/handlers/ruby/module_handler.rb0000644000004100000410000000046212261240652022455 0ustar www-datawww-data# Handles the declaration of a module class YARD::Handlers::Ruby::ModuleHandler < YARD::Handlers::Ruby::Base handles :module namespace_only process do modname = statement[0].source mod = register ModuleObject.new(namespace, modname) parse_block(statement[1], :namespace => mod) end endyard-0.8.7.3/lib/yard/handlers/ruby/class_variable_handler.rb0000644000004100000410000000070012261240652024135 0ustar www-datawww-data# Handles a class variable (@@variable) class YARD::Handlers::Ruby::ClassVariableHandler < YARD::Handlers::Ruby::Base handles :assign namespace_only process do if statement[0].type == :var_field && statement[0][0].type == :cvar name = statement[0][0][0] value = statement[1].source register ClassVariableObject.new(namespace, name) do |o| o.source = statement o.value = value end end end endyard-0.8.7.3/lib/yard/handlers/ruby/yield_handler.rb0000644000004100000410000000202612261240652022274 0ustar www-datawww-data# Handles 'yield' calls class YARD::Handlers::Ruby::YieldHandler < YARD::Handlers::Ruby::Base handles :yield, :yield0 process do return unless owner.is_a?(MethodObject) # Only methods yield return if owner.has_tag? :yield # Don't override yield tags return if owner.has_tag? :yieldparam # Same thing. yieldtag = YARD::Tags::Tag.new(:yield, "", []) if statement.type == :yield statement.jump(:list).children.each do |item| if item == s(:var_ref, s(:kw, "self")) yieldtag.types << '_self' owner.add_tag YARD::Tags::Tag.new(:yieldparam, "the object that the method was called on", owner.namespace.path, '_self') elsif item == s(:zsuper) yieldtag.types << '_super' owner.add_tag YARD::Tags::Tag.new(:yieldparam, "the result of the method from the superclass", nil, '_super') else yieldtag.types << item.source end end end owner.add_tag(yieldtag) unless yieldtag.types.empty? end end yard-0.8.7.3/lib/yard/handlers/ruby/alias_handler.rb0000644000004100000410000000264512261240652022266 0ustar www-datawww-data# Handles alias and alias_method calls class YARD::Handlers::Ruby::AliasHandler < YARD::Handlers::Ruby::Base handles :alias, method_call(:alias_method) namespace_only process do names = [] if statement.type == :alias names = statement.map {|o| o.jump(:ident, :op, :kw, :const).source } elsif statement.call? statement.parameters(false).each do |obj| case obj.type when :symbol_literal, :dyna_symbol names << obj.jump(:ident, :op, :kw, :const).source when :string_literal names << obj.jump(:string_content).source end end end raise YARD::Parser::UndocumentableError, "alias/alias_method" if names.size != 2 new_meth, old_meth = names[0].to_sym, names[1].to_sym old_obj = namespace.child(:name => old_meth, :scope => scope) new_obj = register MethodObject.new(namespace, new_meth, scope) do |o| o.add_file(parser.file, statement.line) end if old_obj new_obj.signature = old_obj.signature new_obj.source = old_obj.source new_obj.docstring = old_obj.docstring + YARD::Docstring.new(statement.comments) new_obj.docstring.line_range = statement.comments_range new_obj.docstring.hash_flag = statement.comments_hash_flag new_obj.docstring.object = new_obj else new_obj.signature = "def #{new_meth}" # this is all we know. end namespace.aliases[new_obj] = old_meth end endyard-0.8.7.3/lib/yard/handlers/ruby/dsl_handler.rb0000644000004100000410000000046612261240652021756 0ustar www-datawww-datamodule YARD module Handlers module Ruby # Handles automatic detection of dsl-style methods class DSLHandler < Base include CodeObjects include DSLHandlerMethods handles method_call namespace_only process { handle_comments } end end end end yard-0.8.7.3/lib/yard/handlers/ruby/exception_handler.rb0000644000004100000410000000147312261240652023171 0ustar www-datawww-data# Handles 'raise' calls inside methods class YARD::Handlers::Ruby::ExceptionHandler < YARD::Handlers::Ruby::Base handles method_call(:raise) process do return unless owner.is_a?(MethodObject) # Only methods yield return if [:command_call, :call].include? statement.type return if owner.has_tag?(:raise) klass = nil if statement.call? params = statement.parameters(false) if params.size == 1 if params.first.ref? && params.first.first.type != :ident klass = params.first.source elsif params.first.call? && params.first.method_name(true) == :new klass = params.first.namespace.source end elsif params.size > 1 klass = params.first.source end end owner.add_tag YARD::Tags::Tag.new(:raise, '', klass) if klass end end yard-0.8.7.3/lib/yard/handlers/ruby/constant_handler.rb0000644000004100000410000000272612261240652023026 0ustar www-datawww-data# Handles any constant assignment class YARD::Handlers::Ruby::ConstantHandler < YARD::Handlers::Ruby::Base include YARD::Handlers::Ruby::StructHandlerMethods handles :assign namespace_only process do if statement[1].call? && statement[1][0][0] == s(:const, "Struct") && statement[1][2] == s(:ident, "new") process_structclass(statement) elsif statement[0].type == :var_field && statement[0][0].type == :const process_constant(statement) end end private def process_constant(statement) name = statement[0][0][0] value = statement[1].source register ConstantObject.new(namespace, name) {|o| o.source = statement; o.value = value.strip } end def process_structclass(statement) lhs = statement[0][0] if lhs.type == :const klass = create_class(lhs[0], P(:Struct)) create_attributes(klass, extract_parameters(statement[1])) else raise YARD::Parser::UndocumentableError, "Struct assignment to #{statement[0].source}" end end # Extract the parameters from the Struct.new AST node, returning them as a list # of strings # # @param [MethodCallNode] superclass the AST node for the Struct.new call # @return [Array] the member names to generate methods for def extract_parameters(superclass) return [] unless superclass.parameters members = superclass.parameters.select {|x| x && x.type == :symbol_literal} members.map! {|x| x.source.strip[1..-1]} members end end yard-0.8.7.3/lib/yard/handlers/ruby/comment_handler.rb0000644000004100000410000000034012261240652022625 0ustar www-datawww-data# Handles any lone comment statement in a Ruby file class YARD::Handlers::Ruby::CommentHandler < YARD::Handlers::Ruby::Base handles :comment, :void_stmt namespace_only process do register_docstring(nil) end end yard-0.8.7.3/lib/yard/handlers/ruby/base.rb0000644000004100000410000001326212261240652020407 0ustar www-datawww-datamodule YARD module Handlers module Ruby # To implement a custom handler matcher, subclass this class and implement # {#matches?} to return whether a node matches the handler. # # @example A Custom Handler Matcher Extension # # Implements a handler that checks for a specific string # # in the node's source. # class MyExtension < HandlesExtension # def matches?(node) node.source.include?(name) end # end # # # This handler will handle any node where the source includes 'foo' # class MyHandler < Handlers::Ruby::Base # handles MyExtension.new('foo') # end class HandlesExtension # Creates a new extension with a specific matcher value +name+ # @param [Object] name the matcher value to check against {#matches?} def initialize(name) @name = name end # Tests if the node matches the handler # @param [Parser::Ruby::AstNode] node a Ruby node # @return [Boolean] whether the +node+ matches the handler def matches?(node) raise NotImplementedError end protected # @return [String] the extension matcher value attr_reader :name end class MethodCallWrapper < HandlesExtension def matches?(node) case node.type when :var_ref if !node.parent || node.parent.type == :list return true if node[0].type == :ident && (name.nil? || node[0][0] == name) end when :fcall, :command, :vcall return true if name.nil? || node[0][0] == name when :call, :command_call return true if name.nil? || node[2][0] == name end false end end class TestNodeWrapper < HandlesExtension def matches?(node) !node.send(name).is_a?(FalseClass) end end # This is the base handler class for the new-style (1.9) Ruby parser. # All handlers that subclass this base class will be used when the # new-style parser is used. For implementing legacy handlers, see # {Legacy::Base}. # # @abstract See {Handlers::Base} for subclassing information. # @see Handlers::Base # @see Legacy::Base class Base < Handlers::Base class << self include Parser::Ruby # @group Statement Matcher Extensions # Matcher for handling any type of method call. Method calls can # be expressed by many {AstNode} types depending on the syntax # with which it is called, so YARD allows you to use this matcher # to simplify matching a method call. # # @example Match the "describe" method call # handles method_call(:describe) # # # The following will be matched: # # describe(...) # # object.describe(...) # # describe "argument" do ... end # # @param [#to_s] name matches the method call of this name # @return [void] def method_call(name = nil) MethodCallWrapper.new(name ? name.to_s : nil) end # Matcher for handling a node with a specific meta-type. An {AstNode} # has a {AstNode#type} to define its type but can also be associated # with a set of types. For instance, +:if+ and +:unless+ are both # of the meta-type +:condition+. # # A meta-type is any method on the {AstNode} class ending in "?", # though you should not include the "?" suffix in your declaration. # Some examples are: "condition", "call", "literal", "kw", "token", # "ref". # # @example Handling any conditional statement (if, unless) # handles meta_type(:condition) # @param [Symbol] type the meta-type to match. A meta-type can be # any method name + "?" that {AstNode} responds to. # @return [void] def meta_type(type) TestNodeWrapper.new(type.to_s + "?") end # @group Testing for a Handler # @return [Boolean] whether or not an {AstNode} object should be # handled by this handler def handles?(node) handlers.any? do |a_handler| case a_handler when Symbol a_handler == node.type when String node.source == a_handler when Regexp node.source =~ a_handler when Parser::Ruby::AstNode a_handler == node when HandlesExtension a_handler.matches?(node) end end end end include Parser::Ruby # @group Parsing an Inner Block def parse_block(inner_node, opts = {}) push_state(opts) do nodes = inner_node.type == :list ? inner_node.children : [inner_node] parser.process(nodes) end end # @group Macro Handling def call_params return [] unless statement.respond_to?(:parameters) statement.parameters(false).compact.map do |param| if param.type == :list param.map {|n| n.jump(:ident, :kw, :tstring_content).source } else param.jump(:ident, :kw, :tstring_content).source end end.flatten end def caller_method if statement.call? || statement.def? statement.method_name(true).to_s elsif statement.type == :var_ref || statement.type == :vcall statement[0].jump(:ident, :kw).source else nil end end end end end endyard-0.8.7.3/lib/yard/handlers/ruby/private_constant_handler.rb0000644000004100000410000000216112261240652024551 0ustar www-datawww-data# Sets visibility of a constant (class, module, const) class YARD::Handlers::Ruby::PrivateConstantHandler < YARD::Handlers::Ruby::Base handles method_call(:private_constant) namespace_only process do errors = [] statement.parameters.each do |param| next unless AstNode === param begin privatize_constant(param) rescue UndocumentableError => err errors << err.message end end if errors.size > 0 msg = errors.size == 1 ? ": #{errors[0]}" : "s: #{errors.join(", ")}" raise UndocumentableError, "private constant#{msg} for #{namespace.path}" end end private def privatize_constant(node) if node.literal? || (node.type == :var_ref && node[0].type == :const) node = node.jump(:tstring_content, :const) const = Proxy.new(namespace, node[0]) ensure_loaded!(const) const.visibility = :private else raise UndocumentableError, "invalid argument to private_constant: #{node.source}" end rescue NamespaceMissingError raise UndocumentableError, "private visibility set on unrecognized constant: #{node[0]}" end endyard-0.8.7.3/lib/yard/docstring.rb0000644000004100000410000003107212261240652016707 0ustar www-datawww-datamodule YARD # A documentation string, or "docstring" for short, encapsulates the # comments and metadata, or "tags", of an object. Meta-data is expressed # in the form +@tag VALUE+, where VALUE can span over multiple lines as # long as they are indented. The following +@example+ tag shows how tags # can be indented: # # # @example My example # # a = "hello world" # # a.reverse # # @version 1.0 # # Tags can be nested in a documentation string, though the {Tags::Tag} # itself is responsible for parsing the inner tags. class Docstring < String class << self # @note Plugin developers should make sure to reset this value # after parsing finishes. This can be done via the # {Parser::SourceParser.after_parse_list} callback. This will # ensure that YARD can properly parse multiple projects in # the same process. # @return [Class] the parser class used to parse # text and optional meta-data from docstrings. Defaults to # {DocstringParser}. # @see DocstringParser # @see Parser::SourceParser.after_parse_list attr_accessor :default_parser # Creates a parser object using the current {default_parser}. # Equivalent to: # Docstring.default_parser.new(*args) # @param args arguments are passed to the {DocstringParser} # class. See {DocstringParser#initialize} for details on # arguments. # @return [DocstringParser] the parser object used to parse a # docstring. def parser(*args) default_parser.new(*args) end end self.default_parser = DocstringParser # @return [Array] the list of reference tags attr_reader :ref_tags # @return [CodeObjects::Base] the object that owns the docstring. attr_accessor :object # @return [Range] line range in the {#object}'s file where the docstring was parsed from attr_accessor :line_range # @return [String] the raw documentation (including raw tag text) attr_reader :all # @return [Boolean] whether the docstring was started with "##" attr_reader :hash_flag def hash_flag=(v) @hash_flag = v == nil ? false : v end # Matches a tag at the start of a comment line # @deprecated Use {DocstringParser::META_MATCH} META_MATCH = DocstringParser::META_MATCH # @group Creating a Docstring Object # Creates a new docstring without performing any parsing through # a {DocstringParser}. This method is called by +DocstringParser+ # when creating the new docstring object. # # @param [String] text the textual portion of the docstring # @param [Array] tags the list of tag objects in the docstring # @param [CodeObjects::Base, nil] object the object associated with the # docstring. May be nil. # @param [String] raw_data the complete docstring, including all # original formatting and any unparsed tags/directives. # @param [CodeObjects::Base, nil] ref_object a reference object used for # the base set of documentation / tag information. def self.new!(text, tags = [], object = nil, raw_data = nil, ref_object = nil) docstring = allocate docstring.replace(text, false) docstring.object = object docstring.add_tag(*tags) docstring.instance_variable_set("@unresolved_reference", ref_object) docstring.instance_variable_set("@all", raw_data) if raw_data docstring end # Creates a new docstring with the raw contents attached to an optional # object. Parsing will be done by the {DocstringParser} class. # # @note To properly parse directives with proper parser context within # handlers, you should not use this method to create a Docstring. # Instead, use the {parser}, which takes a handler object that # can pass parser state onto directives. If a Docstring is created # with this method, directives do not have access to any parser # state, and may not function as expected. # @example # Docstring.new("hello world\n@return Object return", someobj) # # @param [String] content the raw comments to be parsed into a docstring # and associated meta-data. # @param [CodeObjects::Base] object an object to associate the docstring # with. def initialize(content = '', object = nil) @object = object @summary = nil @hash_flag = false self.all = content end # Adds another {Docstring}, copying over tags. # # @param [Docstring, String] other the other docstring (or string) to # add. # @return [Docstring] a new docstring with both docstrings combines def +(other) case other when Docstring Docstring.new([all, other.all].join("\n"), object) else super end end def to_s resolve_reference super end # Replaces the docstring with new raw content. Called by {#all=}. # @param [String] content the raw comments to be parsed def replace(content, parse = true) content = content.join("\n") if content.is_a?(Array) @tags, @ref_tags = [], [] if parse super(parse_comments(content)) else @all = content @unresolved_reference = nil super(content) end end alias all= replace # Deep-copies a docstring # # @note This method creates a new docstring with new tag lists, but does # not create new individual tags. Modifying the tag objects will still # affect the original tags. # @return [Docstring] a new copied docstring # @since 0.7.0 def dup resolve_reference obj = super %w(all summary tags ref_tags).each do |name| val = instance_variable_get("@#{name}") obj.instance_variable_set("@#{name}", val ? val.dup : nil) end obj end # @endgroup # @return [Fixnum] the first line of the {#line_range} # @return [nil] if there is no associated {#line_range} def line line_range ? line_range.first : nil end # Gets the first line of a docstring to the period or the first paragraph. # @return [String] The first line or paragraph of the docstring; always ends with a period. def summary resolve_reference return @summary if @summary stripped = self.gsub(/<.+?>/m, '').gsub(/[\r\n](?![\r\n])/, ' ').strip open_parens = ['{', '(', '['] close_parens = ['}', ')', ']'] num_parens = 0 idx = length.times do |index| case stripped[index, 1] when ".", "\r", "\n" next_char = stripped[index + 1, 1].to_s if num_parens == 0 && next_char =~ /^\s*$/ break index - 1 end when "{", "(", "[" num_parens += 1 when "}", ")", "]" num_parens -= 1 end end @summary = stripped[0..idx] if !@summary.empty? && @summary !~ /\A\s*\{include:.+\}\s*\Z/ @summary += '.' end @summary end # Reformats and returns a raw representation of the tag data using the # current tag and docstring data, not the original text. # # @return [String] the updated raw formatted docstring data # @since 0.7.0 # @todo Add Tags::Tag#to_raw and refactor def to_raw tag_data = tags.sort_by {|t| t.tag_name }.map do |tag| case tag when Tags::OverloadTag tag_text = "@#{tag.tag_name} #{tag.signature}\n" unless tag.docstring.blank? tag_text += "\n" + tag.docstring.all.gsub(/\r?\n/, "\n ") end when Tags::OptionTag tag_text = "@#{tag.tag_name} #{tag.name}" tag_text += ' [' + tag.pair.types.join(', ') + ']' if tag.pair.types tag_text += ' ' + tag.pair.name.to_s if tag.pair.name tag_text += "\n " if tag.name && tag.text tag_text += ' (' + tag.pair.defaults.join(', ') + ')' if tag.pair.defaults tag_text += " " + tag.pair.text.strip.gsub(/\n/, "\n ") if tag.pair.text else tag_text = '@' + tag.tag_name tag_text += ' [' + tag.types.join(', ') + ']' if tag.types tag_text += ' ' + tag.name.to_s if tag.name tag_text += "\n " if tag.name && tag.text tag_text += ' ' + tag.text.strip.gsub(/\n/, "\n ") if tag.text end tag_text end [strip, tag_data.join("\n")].reject {|l| l.empty? }.compact.join("\n") end # @group Creating and Accessing Meta-data # Adds a tag or reftag object to the tag list. If you want to parse # tag data based on the {Tags::DefaultFactory} tag factory, use # {DocstringParser} instead. # # @param [Tags::Tag, Tags::RefTag] tags list of tag objects to add # @return [void] def add_tag(*tags) tags.each_with_index do |tag, i| case tag when Tags::Tag tag.object = object @tags << tag when Tags::RefTag, Tags::RefTagList @ref_tags << tag else raise ArgumentError, "expected Tag or RefTag, got #{tag.class} (at index #{i})" end end end # Convenience method to return the first tag # object in the list of tag objects of that name # # @example # doc = Docstring.new("@return zero when nil") # doc.tag(:return).text # => "zero when nil" # # @param [#to_s] name the tag name to return data for # @return [Tags::Tag] the first tag in the list of {#tags} def tag(name) tags.find {|tag| tag.tag_name.to_s == name.to_s } end # Returns a list of tags specified by +name+ or all tags if +name+ is not specified. # # @param [#to_s] name the tag name to return data for, or nil for all tags # @return [Array] the list of tags by the specified tag name def tags(name = nil) list = @tags + convert_ref_tags return list unless name list.select {|tag| tag.tag_name.to_s == name.to_s } end # Returns true if at least one tag by the name +name+ was declared # # @param [String] name the tag name to search for # @return [Boolean] whether or not the tag +name+ was declared def has_tag?(name) tags.any? {|tag| tag.tag_name.to_s == name.to_s } end # Delete all tags with +name+ # @param [String] name the tag name # @return [void] # @since 0.7.0 def delete_tags(name) delete_tag_if {|tag| tag.tag_name.to_s == name.to_s } end # Deletes all tags where the block returns true # @yieldparam [Tags::Tag] tag the tag that is being tested # @yieldreturn [Boolean] true if the tag should be deleted # @return [void] # @since 0.7.0 def delete_tag_if(&block) @tags.delete_if(&block) @ref_tags.delete_if(&block) end # Returns true if the docstring has no content that is visible to a template. # # @param [Boolean] only_visible_tags whether only {Tags::Library.visible_tags} # should be checked, or if all tags should be considered. # @return [Boolean] whether or not the docstring has content def blank?(only_visible_tags = true) if only_visible_tags empty? && !tags.any? {|tag| Tags::Library.visible_tags.include?(tag.tag_name.to_sym) } else empty? && @tags.empty? && @ref_tags.empty? end end # @endgroup # Resolves unresolved other docstring reference if there is # unresolved reference. Does nothing if there is no unresolved # reference. # # Normally, you don't need to call this method # explicitly. Resolving unresolved reference is done implicitly. # # @return [void] def resolve_reference loop do return if @unresolved_reference.nil? return if CodeObjects::Proxy === @unresolved_reference reference, @unresolved_reference = @unresolved_reference, nil self.all = [reference.docstring.all, @all].join("\n") end end private # Maps valid reference tags # # @return [Array] the list of valid reference tags def convert_ref_tags list = @ref_tags.reject {|t| CodeObjects::Proxy === t.owner } list.map {|t| t.tags }.flatten end # Parses out comments split by newlines into a new code object # # @param [String] comments # the newline delimited array of comments. If the comments # are passed as a String, they will be split by newlines. # # @return [String] the non-metadata portion of the comments to # be used as a docstring def parse_comments(comments) parser = self.class.parser parser.parse(comments, object) @all = parser.raw_text @unresolved_reference = parser.reference add_tag(*parser.tags) parser.text end end end yard-0.8.7.3/lib/yard/templates/0000755000004100000410000000000012261240652016361 5ustar www-datawww-datayard-0.8.7.3/lib/yard/templates/template_options.rb0000644000004100000410000000676512261240652022312 0ustar www-datawww-datarequire 'ostruct' module YARD module Templates # An Options class containing default options for base template rendering. For # options specific to generation of HTML output, see {CLI::YardocOptions}. # # @see CLI::YardocOptions class TemplateOptions < YARD::Options # @return [Symbol] the template output format default_attr :format, :text # @return [Symbol] the template name used to render output default_attr :template, :default # @return [Symbol] the markup format to use when parsing docstrings default_attr :markup, :rdoc # default is :rdoc but falls back on :none # @return [String] the default return type for a method with no return tags default_attr :default_return, "Object" # @return [Boolean] whether void methods should show "void" in their signature default_attr :hide_void_return, false # @return [Boolean] whether code blocks should be syntax highlighted default_attr :highlight, true # @return [Class] the markup provider class for the markup format attr_accessor :markup_provider # @return [OpenStruct] an open struct containing any global state across all # generated objects in a template. default_attr :globals, lambda { OpenStruct.new } alias __globals globals # @return [CodeObjects::Base] the main object being generated in the template attr_accessor :object # @return [CodeObjects::Base] the owner of the generated object attr_accessor :owner # @return [Symbol] the template type used to generate output attr_accessor :type # @return [Boolean] whether serialization should be performed default_attr :serialize, true # @return [Serializers::Base] the serializer used to generate links and serialize # output. Serialization output only occurs if {#serialize} is +true+. attr_accessor :serializer # @deprecated use {#highlight} instead. # @return [Boolean] whether highlighting should be ignored attr_reader :no_highlight undef no_highlight def no_highlight; !highlight end def no_highlight=(value) self.highlight = !value end # @return [String] the title of a given page attr_accessor :page_title # @example A list of mixin path names (including wildcards) # opts.embed_mixins #=> ['ClassMethods', '*Helper', 'YARD::*'] # @return [Array] an array of module name wildcards to embed into # class documentation as if their methods were defined directly in the class. # Useful for modules like ClassMethods. If the name contains '::', the module # is matched against the full mixin path, otherwise only the module name is used. default_attr :embed_mixins, lambda { [] } # @param [CodeObjects::Base] mixin accepts any code object, but returns # nil unless the object is a module. # @return [Boolean] whether a mixin matches the embed_mixins list # @return [nil] if the mixin is not a module object def embed_mixins_match?(mixin) return nil unless mixin.is_a?(CodeObjects::ModuleObject) return nil if mixin == object # the method is not inherited embed_mixins.any? do |embed_mixin| re = /\A#{Regexp.quote(embed_mixin).gsub('\*', '.*')}\Z/ matchstr = embed_mixin.include?("::") ? mixin.path : mixin.name re.match(matchstr.to_s) end end # @return [Verifier] the verifier object attr_accessor :verifier end end end yard-0.8.7.3/lib/yard/templates/erb_cache.rb0000644000004100000410000000103312261240652020576 0ustar www-datawww-datamodule YARD module Templates # @since 0.5.4 module ErbCache def self.method_for(filename, &block) @methods ||= {} return @methods[filename] if @methods[filename] @methods[filename] = name = "_erb_cache_#{@methods.size}" erb = yield.src encoding = erb[/\A(#coding[:=].*\r?\n)/, 1] || '' module_eval "#{encoding}def #{name}; #{erb}; end", filename name end def self.clear! return unless @methods @methods.clear end end end end yard-0.8.7.3/lib/yard/templates/section.rb0000644000004100000410000000452312261240652020356 0ustar www-datawww-datamodule YARD module Templates # Abstracts the structure for a section and its subsections into an ordered # list of sections and subsections. # @since 0.6.0 class Section < Array attr_accessor :name def initialize(name, *args) self.name = name replace(parse_sections(args)) end def dup obj = super obj.name = name obj end def [](*args) if args.first.is_a?(Range) || args.size > 1 obj = super(*args) obj.name = name return obj elsif args.first.is_a?(Integer) return super(*args) end find {|o| o.name == args.first } end def eql?(other) super(other) && name == other.name end def ==(other) case other when Section eql?(other) when Array to_a == other else name == other end end def push(*args) super(*parse_sections(args)) end alias << push def unshift(*args) super(*parse_sections(args)) end def inspect n = name.respond_to?(:path) ? "T('#{name.path}')" : name.inspect subsects = empty? ? "" : ", subsections=#{super}" "Section(#{n}#{subsects})" end def place(*args) super(*parse_sections(args)) end def to_a list = [name] unless empty? subsects = [] each {|s| subsects += s.to_a } list << subsects end list end def any(item) find do |section| return section if section == item return section.any(item) unless section.empty? end nil end private def parse_sections(args) if args.size == 1 && args.first.is_a?(Array) && !args.first.is_a?(Section) args = args.first end sections = [] args.each_with_index do |name, index| case name when Section; sections << name when Array; next else subsections = args[index + 1].is_a?(Array) ? args[index + 1] : [] if subsections.is_a?(Section) subsections = [] end sections << Section.new(name, subsections) end end sections end end end endyard-0.8.7.3/lib/yard/templates/engine.rb0000644000004100000410000001645212261240652020163 0ustar www-datawww-datarequire 'ostruct' module YARD module Templates # This module manages all creation, handling and rendering of {Template} # objects. # # * To create a template object at a path, use {template}. # * To render a template, call {render}. # * To register a template path in the lookup paths, call {register_template_path}. module Engine class << self # @return [Array] the list of registered template paths attr_accessor :template_paths # Registers a new template path in {template_paths} # # @param [String] path a new template path # @return [void] def register_template_path(path) template_paths.push path end # Creates a template module representing the path. Searches on disk # for the first directory named +path+ (joined by '/') within the # template paths and builds a template module for. All other matching # directories in other template paths will be included in the # generated module as mixins (for overriding). # # @param [Array] path a list of path components # @raise [ArgumentError] if the path does not exist within one of the # {template_paths} on disk. # @return [Template] the module representing the template def template(*path) from_template = nil from_template = path.shift if path.first.is_a?(Template) path = path.join('/') full_paths = find_template_paths(from_template, path) path = File.cleanpath(path).gsub('../', '') raise ArgumentError, "No such template for #{path}" if full_paths.empty? mod = template!(path, full_paths) mod end # Forces creation of a template at +path+ within a +full_path+. # # @param [String] path the path name of the template # @param [Array] full_paths the full path on disk of the template # @return [Template] the template module representing the +path+ def template!(path, full_paths = nil) full_paths ||= [path] full_paths = [full_paths] unless full_paths.is_a?(Array) name = template_module_name(full_paths.first) begin; return const_get(name); rescue NameError; end mod = const_set(name, Module.new) mod.send(:include, Template) mod.send(:initialize, path, full_paths) mod end # Renders a template on a {CodeObjects::Base code object} using # a set of default (overridable) options. Either the +:object+ # or +:type+ keys must be provided. # # If a +:serializer+ key is provided and +:serialize+ is not set to # false, the rendered contents will be serialized through the {Serializers::Base} # object. See {with_serializer}. # # @example Renders an object with html formatting # Engine.render(:format => :html, :object => obj) # @example Renders without an object # Engine.render(:type => :fulldoc, :otheropts => somevalue) # @param [Hash] options the options hash # @option options [Symbol] :format (:text) the default format # @option options [Symbol] :type (nil) the :object's type. # @option options [Symbol] :template (:default) the default template # @return [String] the rendered template def render(options = {}) options = set_default_options(options) mod = template(options.template, options.type, options.format) if options.serializer && options.serialize != false with_serializer(options.object, options.serializer) { mod.run(options) } else mod.run(options) end end # Passes a set of objects to the +:fulldoc+ template for full documentation generation. # This is called by {CLI::Yardoc} to most commonly perform HTML # documentation generation. # # @param [Array] objects a list of {CodeObjects::Base} # objects to pass to the template # @param [Hash] options (see {render}) # @return [void] def generate(objects, options = {}) options = set_default_options(options) options.objects = objects options.object = Registry.root template(options.template, :fulldoc, options.format).run(options) end # Serializes the results of a block with a +serializer+ object. # # @param [CodeObjects::Base] object the code object to serialize # @param [Serializers::Base] serializer the serializer object # @yield a block whose result will be serialize # @yieldreturn [String] the contents to serialize # @see Serializers::Base def with_serializer(object, serializer, &block) output = nil filename = serializer.serialized_path(object) if serializer.respond_to?(:basepath) filename = File.join(serializer.basepath, filename) end log.capture("Generating #{filename}", nil) do serializer.before_serialize if serializer output = yield if serializer serializer.serialize(object, output) serializer.after_serialize(output) end end output end private # Sets default options on the options hash # # @param [Hash] options the options hash # @option options [Symbol] :format (:text) the default format # @option options [Symbol] :type (nil) the :object's type, if provided # @option options [Symbol] :template (:default) the default template # @return [void] def set_default_options(options = {}) if options.is_a?(Hash) options = TemplateOptions.new.tap do |o| o.reset_defaults o.update(options) end end options.type ||= options.object.type if options.object options end # Searches through the registered {template_paths} and returns # all full directories that have the +path+ within them on disk. # # @param [Template] from_template if provided, allows a relative # path to be specified from this template's full path. # @param [String] path the path component to search for in the # {template_paths} # @return [Array] a list of full paths that are existing # candidates for a template module def find_template_paths(from_template, path) paths = template_paths.dup paths = from_template.full_paths + paths if from_template paths.inject([]) do |acc, tp| full_path = File.cleanpath(File.join(tp, path)) acc.unshift(full_path) if File.directory?(full_path) acc end.uniq end # The name of the module that represents a +path+ # # @param [String] path the path to generate a module name for # @return [String] the module name def template_module_name(path) 'Template_' + path.to_s.gsub(/[^a-z0-9]/i, '_') end end self.template_paths = [] end Engine.register_template_path(File.join(YARD::ROOT, '..', 'templates')) end end yard-0.8.7.3/lib/yard/templates/helpers/0000755000004100000410000000000012261240652020023 5ustar www-datawww-datayard-0.8.7.3/lib/yard/templates/helpers/markup/0000755000004100000410000000000012261240652021322 5ustar www-datawww-datayard-0.8.7.3/lib/yard/templates/helpers/markup/rdoc_markdown.rb0000644000004100000410000000077712261240652024513 0ustar www-datawww-datamodule YARD module Templates module Helpers module Markup begin require 'rdoc'; rescue LoadError; end begin require 'rdoc/markdown' rescue LoadError raise NameError, "could not load RDoc Markdown support (rdoc is too old)" end class RDocMarkdown < RDocMarkup def initialize(text) super RDoc::Markdown.new.parse(text) end def fix_typewriter(html) html end end end end end end yard-0.8.7.3/lib/yard/templates/helpers/markup/rdoc_markup.rb0000644000004100000410000000613312261240652024160 0ustar www-datawww-datarequire 'thread' module YARD module Templates module Helpers module Markup begin require 'rdoc'; rescue LoadError; end begin require 'rdoc/markup' require 'rdoc/markup/to_html' class RDocMarkup; MARKUP = RDoc::Markup end class RDocMarkupToHtml < RDoc::Markup::ToHtml if defined?(RDoc::VERSION) && RDoc::VERSION >= '4.0.0' && defined?(RDoc::Options) then def initialize options = RDoc::Options.new options.pipe = true super(options) end end end rescue LoadError begin require 'rdoc/markup/simple_markup' require 'rdoc/markup/simple_markup/to_html' class RDocMarkup; MARKUP = SM::SimpleMarkup end class RDocMarkupToHtml < SM::ToHtml; end rescue LoadError raise NameError, "could not load RDocMarkup (rdoc is not installed)" end end class RDocMarkup attr_accessor :from_path @@formatter = nil @@markup = nil @@mutex = nil def initialize(text) @text = text @@formatter ||= RDocMarkupToHtml.new @@markup ||= MARKUP.new @@mutex ||= Mutex.new end def to_html html = nil @@mutex.synchronize do @@formatter.from_path = from_path html = @@markup.convert(@text, @@formatter) end html = fix_dash_dash(html) html = fix_typewriter(html) html end private # Fixes RDoc behaviour with ++ only supporting alphanumeric text. # # @todo Refactor into own SimpleMarkup subclass def fix_typewriter(text) code_tags = 0 text.gsub(/<(\/)?(pre|code|tt)|(\s|^|>)\+(?! )([^\n\+]{1,900})(?! )\+/) do |str| closed, tag, first_text, type_text, pre_text, no_match = $1, $2, $3, $4, $`, $& if tag code_tags += (closed ? -1 : 1) next str end next str unless code_tags == 0 first_text + '' + type_text + '' end end # Don't allow -- to turn into — element. The chances of this being # some --option is far more likely than the typographical meaning. # # @todo Refactor into own SimpleMarkup subclass def fix_dash_dash(text) text.gsub(/—(?=\S)/, '--') end end class RDocMarkupToHtml attr_accessor :from_path # Disable auto-link of URLs def handle_special_HYPERLINK(special) @hyperlink ? special.text : super end def accept_paragraph(*args) par = args.last text = par.respond_to?(:txt) ? par.txt : par.text @hyperlink = !!(text =~ /\{(https?:|mailto:|link:|www\.)/) super end end end end end endyard-0.8.7.3/lib/yard/templates/helpers/html_syntax_highlight_helper.rb0000644000004100000410000000426512261240652026317 0ustar www-datawww-datamodule YARD module Templates module Helpers # Helper methods for syntax highlighting. module HtmlSyntaxHighlightHelper # Highlights Ruby source # @param [String] source the Ruby source code # @return [String] the highlighted Ruby source def html_syntax_highlight_ruby(source) if Parser::SourceParser.parser_type == :ruby html_syntax_highlight_ruby_ripper(source) else html_syntax_highlight_ruby_legacy(source) end end private def html_syntax_highlight_ruby_ripper(source) tokenlist = Parser::Ruby::RubyParser.parse(source, "(syntax_highlight)").tokens raise Parser::ParserSyntaxError if tokenlist.empty? && !source.empty? output = "" tokenlist.each do |s| output << "" if [:tstring_beg, :regexp_beg].include?(s[0]) case s.first when :nl, :ignored_nl, :sp output << h(s[1]) when :ident output << "#{h(s[1])}" else output << "#{h(s[1])}" end output << "" if [:tstring_end, :regexp_end].include?(s[0]) end output rescue Parser::ParserSyntaxError h(source) end def html_syntax_highlight_ruby_legacy(source) tokenlist = Parser::Ruby::Legacy::TokenList.new(source) tokenlist.map do |s| prettyclass = s.class.class_name.sub(/^Tk/, '').downcase prettysuper = s.class.superclass.class_name.sub(/^Tk/, '').downcase case s when Parser::Ruby::Legacy::RubyToken::TkWhitespace, Parser::Ruby::Legacy::RubyToken::TkUnknownChar h s.text when Parser::Ruby::Legacy::RubyToken::TkId prettyval = h(s.text) "#{prettyval}" else "#{h s.text}" end end.join end end end end endyard-0.8.7.3/lib/yard/templates/helpers/base_helper.rb0000644000004100000410000001551712261240652022632 0ustar www-datawww-datamodule YARD::Templates::Helpers # The base helper module included in all templates. module BaseHelper attr_accessor :object, :serializer # @return [CodeObjects::Base] the object representing the current generated # page. Might not be the current {#object} when inside sub-templates. attr_reader :owner undef owner def owner; @owner || object.namespace end # @group Managing Global Template State # An object that keeps track of global state throughout the entire template # rendering process (including any sub-templates). # # @return [OpenStruct] a struct object that stores state # @since 0.6.0 def globals; options.globals end # @group Running the Verifier # Runs a list of objects against the {Verifier} object passed into the # template and returns the subset of verified objects. # # @param [Array] list a list of code objects # @return [Array] a list of code objects that match # the verifier. If no verifier is supplied, all objects are returned. def run_verifier(list) options.verifier ? options.verifier.run(list) : list end # @group Escaping Text # Escapes text. This is used a lot by the HtmlHelper and there should # be some helper to "clean up" text for whatever, this is it. def h(text) text end # @group Linking Objects and URLs # Links objects or URLs. This method will delegate to the correct +link_+ # method depending on the arguments passed in. # # @example Linking a URL # linkify('http://example.com') # @example Including docstring contents of an object # linkify('include:YARD::Docstring') # @example Linking to an extra file # linkify('file:README') # @example Linking an object by path # linkify('YARD::Docstring') def linkify(*args) if args.first.is_a?(String) case args.first when %r{://}, /^mailto:/ link_url(args[0], args[1], {:target => '_parent'}.merge(args[2]||{})) when /^include:file:(\S+)/ file = $1 relpath = File.relative_path(Dir.pwd, File.expand_path(file)) if relpath =~ /^\.\./ log.warn "Cannot include file from path `#{file}'" "" elsif File.file?(file) link_include_file(file) else log.warn "Cannot find file at `#{file}' for inclusion" "" end when /^include:(\S+)/ path = $1 if obj = YARD::Registry.resolve(object.namespace, path) link_include_object(obj) else log.warn "Cannot find object at `#{path}' for inclusion" "" end when /^render:(\S+)/ path = $1 if obj = YARD::Registry.resolve(object, path) opts = options.dup opts.delete(:serializer) obj.format(opts) else '' end when /^file:(\S+?)(?:#(\S+))?$/ link_file($1, args[1] ? args[1] : nil, $2) else link_object(*args) end else link_object(*args) end end # Includes an object's docstring into output. # @since 0.6.0 # @param [CodeObjects::Base] obj the object to include # @return [String] the object's docstring (no tags) def link_include_object(obj) obj.docstring end # Include a file as a docstring in output # @since 0.7.0 # @param [String] file the filename to include # @return [String] the file's contents def link_include_file(file) File.read(file) end # Links to an object with an optional title # # @param [CodeObjects::Base] obj the object to link to # @param [String] title the title to use for the link # @return [String] the linked object def link_object(obj, title = nil) return title if title case obj when YARD::CodeObjects::Base, YARD::CodeObjects::Proxy obj.title when String, Symbol P(obj).title else obj end end # Links to a URL # # @param [String] url the URL to link to # @param [String] title the optional title to display the link as # @param [Hash] params optional parameters for the link # @return [String] the linked URL def link_url(url, title = nil, params = nil) url end # Links to an extra file # # @param [String] filename the filename to link to # @param [String] title the title of the link # @param [String] anchor optional anchor # @return [String] the link to the file # @since 0.5.5 def link_file(filename, title = nil, anchor = nil) return filename.filename if CodeObjects::ExtraFileObject === filename filename end # @group Formatting Object Attributes # Formats a list of return types for output and links each type. # # @example Formatting types # format_types(['String', 'Array']) #=> "(String, Array)" # @example Formatting types without surrounding brackets # format_types(['String', 'Array'], false) #=> "String, Array" # @param [Array] list a list of types # @param [Boolean] brackets whether to surround the types in brackets # @return [String] the formatted list of Ruby types def format_types(list, brackets = true) list.nil? || list.empty? ? "" : (brackets ? "(#{list.join(", ")})" : list.join(", ")) end # @example Formatted type of an exception class # o = ClassObject.new(:root, :MyError) # o.superclass = P('RuntimeError') # format_object_type(o) # => "Exception" # @example Formatted type of a method # o = MethodObject.new(:root, :to_s) # format_object_type(o) # => "Method" # @param [CodeObjects::Base] object the object to retrieve the type for # @return [String] the human-readable formatted {CodeObjects::Base#type #type} # for the object def format_object_type(object) case object when YARD::CodeObjects::ClassObject object.is_exception? ? "Exception" : "Class" else object.type.to_s.capitalize end end # @example # s = format_object_title ModuleObject.new(:root, :MyModuleName) # s # => "Module: MyModuleName" # @param [CodeObjects::Base] object the object to retrieve a title for # @return [String] the page title name for a given object def format_object_title(object) case object when YARD::CodeObjects::RootObject "Top Level Namespace" else format_object_type(object) + ": " + object.title end end # Indents and formats source code # # @param [String] value the input source code # @return [String] formatted source code def format_source(value) sp = value.split("\n").last[/^(\s+)/, 1] num = sp ? sp.size : 0 value.gsub(/^\s{#{num}}/, '') end end end yard-0.8.7.3/lib/yard/templates/helpers/html_helper.rb0000644000004100000410000005167712261240652022673 0ustar www-datawww-datarequire 'cgi' module YARD module Templates::Helpers # The helper module for HTML templates. module HtmlHelper include MarkupHelper include HtmlSyntaxHighlightHelper # @group Escaping Template Data # Escapes HTML entities # # @param [String] text the text to escape # @return [String] the HTML with escaped entities def h(text) CGI.escapeHTML(text.to_s) end # Escapes a URL # # @param [String] text the URL # @return [String] the escaped URL def urlencode(text) CGI.escape(text.to_s) end # @group Converting Markup to HTML # Turns text into HTML using +markup+ style formatting. # # @param [String] text the text to format # @param [Symbol] markup examples are +:markdown+, +:textile+, +:rdoc+. # To add a custom markup type, see {MarkupHelper} # @return [String] the HTML def htmlify(text, markup = options.markup) markup_meth = "html_markup_#{markup}" return text unless respond_to?(markup_meth) return "" unless text return text unless markup html = send(markup_meth, text) if html.respond_to?(:encode) html = html.force_encoding(text.encoding) # for libs that mess with encoding html = html.encode(:invalid => :replace, :replace => '?') end html = resolve_links(html) unless [:text, :none, :pre].include?(markup) html = parse_codeblocks(html) end html end # Converts Markdown to HTML # @param [String] text input Markdown text # @return [String] output HTML # @since 0.6.0 def html_markup_markdown(text) # TODO: other libraries might be more complex provider = markup_class(:markdown) if provider.to_s == 'RDiscount' provider.new(text, :autolink).to_html elsif provider.to_s == 'RedcarpetCompat' provider.new(text, :no_intraemphasis, :gh_blockcode, :fenced_code, :autolink).to_html else provider.new(text).to_html end end # Converts Asciidoc to HTML # @param [String] text input Asciidoc text # @return [String] output HTML def html_markup_asciidoc(text) markup_class(:asciidoc).render(text) end # Converts Textile to HTML # @param [String] text the input Textile text # @return [String] output HTML # @since 0.6.0 def html_markup_textile(text) doc = markup_class(:textile).new(text) doc.hard_breaks = false if doc.respond_to?(:hard_breaks=) doc.to_html end # Converts plaintext to strict Textile (hard breaks) # @param [String] text the input textile data # @return [String] the output HTML # @since 0.6.0 def html_markup_textile_strict(text) markup_class(:textile).new(text).to_html end # Converts RDoc formatting (SimpleMarkup) to HTML # @param [String] text the input RDoc formatted text # @return [String] output HTML # @since 0.6.0 def html_markup_rdoc(text) doc = markup_class(:rdoc).new(text) doc.from_path = url_for(object) if doc.respond_to?(:from_path=) doc.to_html end # Converts plaintext to pre-formatted HTML # @param [String] text the input text # @return [String] the output HTML # @since 0.6.0 def html_markup_pre(text) "
            " + h(text) + "
            " end # Converts plaintext to regular HTML # @param [String] text the input text # @return [String] the output HTML # @since 0.6.0 def html_markup_text(text) h(text).gsub(/\r?\n/, '
            ') end # @return [String] the same text with no markup # @since 0.6.6 def html_markup_none(text) h(text) end # Converts HTML to HTML # @param [String] text input html # @return [String] output HTML # @since 0.6.0 def html_markup_html(text) text end # Highlights Ruby source. Similar to {#html_syntax_highlight}, but # this method is meant to be called from {#htmlify} when markup is # set to "ruby". # # @param [String] source the Ruby source # @return [String] the highlighted HTML # @since 0.7.0 def html_markup_ruby(source) '
            ' + html_syntax_highlight(source, :ruby) + '
            ' end # @return [String] HTMLified text as a single line (paragraphs removed) def htmlify_line(*args) "
            " + htmlify(*args) + "
            " end # @group Syntax Highlighting Source Code # Syntax highlights +source+ in language +type+. # # @note To support a specific language +type+, implement the method # +html_syntax_highlight_TYPE+ in this class. # # @param [String] source the source code to highlight # @param [Symbol, String] type the language type (:ruby, :plain, etc). Use # :plain for no syntax highlighting. # @return [String] the highlighted source def html_syntax_highlight(source, type = nil) return "" unless source return h(source) unless options.highlight new_type, source = parse_lang_for_codeblock(source) type ||= new_type || :ruby meth = "html_syntax_highlight_#{type}" respond_to?(meth) ? send(meth, source) : h(source) end # @return [String] unhighlighted source def html_syntax_highlight_plain(source) h(source) end # @group Linking Objects and URLs # Resolves any text in the form of +{Name}+ to the object specified by # Name. Also supports link titles in the form +{Name title}+. # # @example Linking to an instance method # resolve_links("{MyClass#method}") # => "MyClass#method" # @example Linking to a class with a title # resolve_links("{A::B::C the C class}") # => "the c class" # @param [String] text the text to resolve links in # @return [String] HTML with linkified references def resolve_links(text) code_tags = 0 text.gsub(/<(\/)?(pre|code|tt)|(\\|!)?\{(?!\})(\S+?)(?:\s([^\}]*?\S))?\}(?=[\W<]|.+<\/|$)/m) do |str| closed, tag, escape, name, title, match = $1, $2, $3, $4, $5, $& if tag code_tags += (closed ? -1 : 1) next str end next str unless code_tags == 0 next(match[1..-1]) if escape next(match) if name[0,1] == '|' if name == '.*<\/a>\s*(.*)\Z/ name, title = $1, $2 title = nil if title.empty? end name = CGI.unescapeHTML(name) if object.is_a?(String) object else link = linkify(name, title) if (link == name || link == title) && (name+' '+link !~ /\A/) match = /(.+)?(\{#{Regexp.quote name}(?:\s.*?)?\})(.+)?/.match(text) file = (@file ? @file.filename : object.file) || '(unknown)' line = (@file ? 1 : (object.docstring.line_range ? object.docstring.line_range.first : 1)) + (match ? $`.count("\n") : 0) log.warn "In file `#{file}':#{line}: Cannot resolve link to #{name} from text" + (match ? ":" : ".") log.warn((match[1] ? '...' : '') + match[2].gsub("\n","") + (match[3] ? '...' : '')) if match end link end end end # (see BaseHelper#link_file) def link_file(filename, title = nil, anchor = nil) if CodeObjects::ExtraFileObject === filename file = filename else contents = File.file?(filename) ? nil : '' file = CodeObjects::ExtraFileObject.new(filename, contents) end return title || file.title unless serializer link_url(url_for_file(file, anchor), title || file.title) end # (see BaseHelper#link_include_file) def link_include_file(file) unless file.is_a?(CodeObjects::ExtraFileObject) file = CodeObjects::ExtraFileObject.new(file) end file.attributes[:markup] ||= markup_for_file('', file.filename) htmlify(file.contents, file.attributes[:markup] || options.markup) end # (see BaseHelper#link_include_object) def link_include_object(obj) htmlify(obj.docstring) end # (see BaseHelper#link_object) def link_object(obj, title = nil, anchor = nil, relative = true) return title if obj.nil? obj = Registry.resolve(object, obj, true, true) if obj.is_a?(String) if title title = title.to_s elsif object.is_a?(CodeObjects::Base) # Check if we're linking to a class method in the current # object. If we are, create a title in the format of # "CurrentClass.method_name" if obj.is_a?(CodeObjects::MethodObject) && obj.scope == :class && obj.parent == object title = h([object.name, obj.sep, obj.name].join) elsif obj.title != obj.path title = h(obj.title) else title = h(object.relative_path(obj)) end else title = h(obj.to_s) end return title unless serializer return title if obj.is_a?(CodeObjects::Proxy) link = url_for(obj, anchor, relative) link = link ? link_url(link, title, :title => h("#{obj.title} (#{obj.type})")) : title "" + link + "" end # (see BaseHelper#link_url) def link_url(url, title = nil, params = {}) title ||= url title.gsub!(/[\r\n]/, ' ') params = SymbolHash.new(false).update( :href => url, :title => h(title) ).update(params) params[:target] ||= '_parent' if url =~ /^(\w+):\/\// "#{title}".gsub(/[\r\n]/, ' ') end # @group URL Helpers # @param [CodeObjects::Base] object the object to get an anchor for # @return [String] the anchor for a specific object def anchor_for(object) case object when CodeObjects::MethodObject "#{object.name}-#{object.scope}_#{object.type}" when CodeObjects::ClassVariableObject "#{object.name.to_s.gsub('@@', '')}-#{object.type}" when CodeObjects::Base "#{object.name}-#{object.type}" when CodeObjects::Proxy object.path else object.to_s end end # Returns the URL for an object. # # @param [String, CodeObjects::Base] obj the object (or object path) to link to # @param [String] anchor the anchor to link to # @param [Boolean] relative use a relative or absolute link # @return [String] the URL location of the object def url_for(obj, anchor = nil, relative = true) link = nil return link unless serializer return link if obj.is_a?(CodeObjects::Base) && run_verifier([obj]).empty? if obj.is_a?(CodeObjects::Base) && !obj.is_a?(CodeObjects::NamespaceObject) # If the obj is not a namespace obj make it the anchor. anchor, obj = obj, obj.namespace end objpath = serializer.serialized_path(obj) return link unless objpath if relative fromobj = object if object.is_a?(CodeObjects::Base) && !object.is_a?(CodeObjects::NamespaceObject) fromobj = owner end from = serializer.serialized_path(fromobj) link = File.relative_path(from, objpath) else link = objpath end link + (anchor ? '#' + urlencode(anchor_for(anchor)) : '') end # Returns the URL for a specific file # # @param [String, CodeObjects::ExtraFileObject] filename the filename to link to # @param [String] anchor optional anchor # @return [String] the URL pointing to the file def url_for_file(filename, anchor = nil) return '' unless serializer fromobj = object if CodeObjects::Base === fromobj && !fromobj.is_a?(CodeObjects::NamespaceObject) fromobj = fromobj.namespace end from = serializer.serialized_path(fromobj) if filename == options.readme path = 'index.html' else path = serializer.serialized_path(filename) end link = File.relative_path(from, path) link += (anchor ? '#' + urlencode(anchor) : '') link end # Returns the URL for a list type # # @param [String, Symbol] type the list type to generate a URL for # @return [String] the URL pointing to the list # @since 0.8.0 def url_for_list(type) url_for_file("#{type}_list.html") end # Returns the URL for the frameset page # # @return [String] the URL pointing to the frames page # @since 0.8.0 def url_for_frameset url_for_file("frames.html") end # Returns the URL for the main page (README or alphabetic index) # # @return [String] the URL pointing to the first main page the # user should see. def url_for_main url_for_file("index.html") end # Returns the URL for the alphabetic index page # # @return [String] the URL pointing to the first main page the # user should see. def url_for_index url_for_file("_index.html") end # @group Formatting Objects and Attributes # Formats a list of objects and links them # @return [String] a formatted list of objects def format_object_name_list(objects) objects.sort_by {|o| o.name.to_s.downcase }.map do |o| "" + linkify(o, o.name) + "" end.join(", ") end # Formats a list of types from a tag. # # @param [Array, FalseClass] typelist # the list of types to be formatted. # # @param [Boolean] brackets omits the surrounding # brackets if +brackets+ is set to +false+. # # @return [String] the list of types formatted # as [Type1, Type2, ...] with the types linked # to their respective descriptions. # def format_types(typelist, brackets = true) return unless typelist.is_a?(Array) list = typelist.map do |type| type = type.gsub(/([<>])/) { h($1) } type = type.gsub(/([\w:]+)/) { $1 == "lt" || $1 == "gt" ? $1 : linkify($1, $1) } "" + type + "" end list.empty? ? "" : (brackets ? "(#{list.join(", ")})" : list.join(", ")) end # Get the return types for a method signature. # # @param [CodeObjects::MethodObject] meth the method object # @param [Boolean] link whether to link the types # @return [String] the signature types # @since 0.5.3 def signature_types(meth, link = true) meth = convert_method_to_overload(meth) if meth.respond_to?(:object) && !meth.has_tag?(:return) meth = meth.object end type = options.default_return || "" if meth.tag(:return) && meth.tag(:return).types types = meth.tags(:return).map {|t| t.types ? t.types : [] }.flatten.uniq first = link ? h(types.first) : format_types([types.first], false) if types.size == 2 && types.last == 'nil' type = first + '?' elsif types.size == 2 && types.last =~ /^(Array)?<#{Regexp.quote types.first}>$/ type = first + '+' elsif types.size > 2 type = [first, '...'].join(', ') elsif types == ['void'] && options.hide_void_return type = "" else type = link ? h(types.join(", ")) : format_types(types, false) end elsif !type.empty? type = link ? h(type) : format_types([type], false) end type = "(#{type}) " unless type.empty? type end # Formats the signature of method +meth+. # # @param [CodeObjects::MethodObject] meth the method object to list # the signature of # @param [Boolean] link whether to link the method signature to the details view # @param [Boolean] show_extras whether to show extra meta-data (visibility, attribute info) # @param [Boolean] full_attr_name whether to show the full attribute name # ("name=" instead of "name") # @return [String] the formatted method signature def signature(meth, link = true, show_extras = true, full_attr_name = true) meth = convert_method_to_overload(meth) type = signature_types(meth, link) scope = meth.scope == :class ? "+" : "-" name = full_attr_name ? meth.name : meth.name.to_s.gsub(/^(\w+)=$/, '\1') blk = format_block(meth) args = !full_attr_name && meth.writer? ? "" : format_args(meth) extras = [] extras_text = '' if show_extras if rw = meth.attr_info attname = [rw[:read] ? 'read' : nil, rw[:write] ? 'write' : nil].compact attname = attname.size == 1 ? attname.join('') + 'only' : nil extras << attname if attname end extras << meth.visibility if meth.visibility != :public extras_text = ' (' + extras.join(", ") + ')' unless extras.empty? end title = "%s %s%s%s %s" % [scope, type, h(name), args, blk] if link if meth.is_a?(YARD::CodeObjects::MethodObject) link_title = "#{h meth.name(true)} (#{meth.scope} #{meth.type})" else link_title = "#{h name} (#{meth.type})" end obj = meth.respond_to?(:object) ? meth.object : meth url = url_for(object, obj) link_url(url, title, :title => link_title) + extras_text else title + extras_text end end # @group Getting the Character Encoding # Returns the current character set. The default value can be overridden # by setting the +LANG+ environment variable or by overriding this # method. In Ruby 1.9 you can also modify this value by setting # +Encoding.default_external+. # # @return [String] the current character set # @since 0.5.4 def charset has_encoding = defined?(::Encoding) if @file && has_encoding lang = @file.contents.encoding.to_s else return 'utf-8' unless has_encoding || lang = ENV['LANG'] if has_encoding lang = ::Encoding.default_external.name.downcase else lang = lang.downcase.split('.').last end end case lang when "ascii-8bit", "us-ascii", "ascii-7bit"; 'iso-8859-1' when "utf8"; 'utf-8' else; lang end end # @endgroup private # Converts a set of hash options into HTML attributes for a tag # # @param [Hash{String => String}] opts the tag options # @return [String] the tag attributes of an HTML tag def tag_attrs(opts = {}) opts.sort_by {|k, v| k.to_s }.map {|k,v| "#{k}=#{v.to_s.inspect}" if v }.join(" ") end # Converts a {CodeObjects::MethodObject} into an overload object # @since 0.5.3 def convert_method_to_overload(meth) # use first overload tag if it has a return type and method itself does not if !meth.tag(:return) && meth.tags(:overload).size == 1 && meth.tag(:overload).tag(:return) return meth.tag(:overload) end meth end # Parses !!!lang out of codeblock, returning the codeblock language # followed by the source code. # # @param [String] source the source code whose language to determine # @return [Array(String, String)] the language, if any, and the # remaining source # @since 0.7.5 def parse_lang_for_codeblock(source) type = nil if source =~ /\A(?:[ \t]*\r?\n)?[ \t]*!!!([\w.+-]+)[ \t]*\r?\n/ type, source = $1, $' end [type, source] end # Parses code blocks out of html and performs syntax highlighting # on code inside of the blocks. # # @param [String] html the html to search for code in # @return [String] highlighted html # @see #html_syntax_highlight def parse_codeblocks(html) html.gsub(/(?:\s*)?(.+?)(?:<\/code>\s*)?<\/pre>/m) do string = $3 # handle !!!LANG prefix to send to html_syntax_highlight_LANG language, _ = parse_lang_for_codeblock(string) language ||= $1 || $2 || object.source_type if options.highlight string = html_syntax_highlight(CGI.unescapeHTML(string), language) end classes = ['code', language].compact.join(' ') %Q{
            #{string}
            } end end end end end yard-0.8.7.3/lib/yard/templates/helpers/uml_helper.rb0000644000004100000410000000263212261240652022507 0ustar www-datawww-datamodule YARD module Templates::Helpers # Helpers for UML template format module UMLHelper # Official UML visibility prefix syntax for an object given its visibility # @param [CodeObjects::Base] object the object to retrieve visibility for # @return [String] the UML visibility prefix def uml_visibility(object) case object.visibility when :public; '+' when :protected; '#' when :private; '-' end end # Formats the path of an object for Graphviz syntax # @param [CodeObjects::Base] object an object to format the path of # @return [String] the encoded path def format_path(object) object.path.gsub('::', '_') end # Encodes text in escaped Graphviz syntax # @param [String] text text to encode # @return [String] the encoded text def h(text) text.to_s.gsub(/(\W)/, '\\\\\1') end # Tidies data by formatting and indenting text # @param [String] data pre-formatted text # @return [String] tidied text. def tidy(data) indent = 0 data.split(/\n/).map do |line| line.gsub!(/^\s*/, '') next if line.empty? indent -= 1 if line =~ /^\s*\}\s*$/ line = (' ' * (indent * 2)) + line indent += 1 if line =~ /\{\s*$/ line end.compact.join("\n") + "\n" end end end endyard-0.8.7.3/lib/yard/templates/helpers/markup_helper.rb0000644000004100000410000001445112261240652023213 0ustar www-datawww-datarequire 'rubygems' module YARD module Templates::Helpers # Helper methods for loading and managing markup types. module MarkupHelper class << self # Clears the markup provider cache information. Mainly used for testing. # @return [void] def clear_markup_cache self.markup_cache = {} end # @return [Hash{Symbol=>{(:provider,:class)=>Object}}] the cached markup providers # @private # @since 0.6.4 attr_accessor :markup_cache end MarkupHelper.clear_markup_cache # The default list of markup providers for each markup type MARKUP_PROVIDERS = { :markdown => [ {:lib => :redcarpet, :const => 'RedcarpetCompat'}, {:lib => :rdiscount, :const => 'RDiscount'}, {:lib => :kramdown, :const => 'Kramdown::Document'}, {:lib => :bluecloth, :const => 'BlueCloth'}, {:lib => :maruku, :const => 'Maruku'}, {:lib => :'rpeg-markdown', :const => 'PEGMarkdown'}, {:lib => :rdoc, :const => 'YARD::Templates::Helpers::Markup::RDocMarkdown'}, ], :textile => [ {:lib => :redcloth, :const => 'RedCloth'}, ], :textile_strict => [ {:lib => :redcloth, :const => 'RedCloth'}, ], :rdoc => [ {:lib => nil, :const => 'YARD::Templates::Helpers::Markup::RDocMarkup'}, ], :asciidoc => [ {:lib => :asciidoctor, :const => 'Asciidoctor'} ], :ruby => [], :text => [], :pre => [], :html => [], :none => [], } # Returns a list of extensions for various markup types. To register # extensions for a type, add them to the array of extensions for the # type. # @since 0.6.0 MARKUP_EXTENSIONS = { :html => ['htm', 'html', 'shtml'], :text => ['txt'], :textile => ['textile', 'txtile'], :asciidoc => ['asciidoc', 'ad', 'adoc', 'asc'], :markdown => ['markdown', 'md', 'mdown', 'mkd'], :rdoc => ['rdoc'], :ruby => ['rb', 'ru'] } # Contains the Regexp object that matches the shebang line of extra # files to detect the markup type. MARKUP_FILE_SHEBANG = /\A#!(\S+)\s*$/ # Attempts to load the first valid markup provider in {MARKUP_PROVIDERS}. # If a provider is specified, immediately try to load it. # # On success this sets `@markup_provider` and `@markup_class` to # the provider name and library constant class/module respectively for # the loaded provider. # # On failure this method will inform the user that no provider could be # found and exit the program. # # @return [Boolean] whether the markup provider was successfully loaded. def load_markup_provider(type = options.markup) return true if MarkupHelper.markup_cache[type] MarkupHelper.markup_cache[type] ||= {} providers = MARKUP_PROVIDERS[type.to_sym] return true if providers && providers.empty? if providers && options.markup_provider providers = providers.select {|p| p[:lib] == options.markup_provider } end if providers == nil || providers.empty? log.error "Invalid markup type '#{type}' or markup provider " + "(#{options.markup_provider}) is not registered." return false end # Search for provider, return the library class name as const if found providers.each do |provider| begin require provider[:lib].to_s; rescue LoadError; next end if provider[:lib] begin klass = eval("::" + provider[:const]); rescue NameError; next end MarkupHelper.markup_cache[type][:provider] = provider[:lib] # Cache the provider MarkupHelper.markup_cache[type][:class] = klass return true end # Show error message telling user to install first potential provider name, lib = *[providers.first[:const], providers.first[:lib] || type] log.error "Missing '#{lib}' gem for #{type.to_s.capitalize} formatting. Install it with `gem install #{lib}`" false end # Checks for a shebang or looks at the file extension to determine # the markup type for the file contents. File extensions are registered # for a markup type in {MARKUP_EXTENSIONS}. # # A shebang should be on the first line of a file and be in the form: # # #!markup_type # # Standard markup types are text, html, rdoc, markdown, textile # # @param [String] contents Unused. Was necessary prior to 0.7.0. # Newer versions of YARD use {CodeObjects::ExtraFileObject#contents} # @return [Symbol] the markup type recognized for the file # @see MARKUP_EXTENSIONS # @since 0.6.0 def markup_for_file(contents, filename) if contents && contents =~ MARKUP_FILE_SHEBANG # Shebang support return $1.to_sym end ext = (File.extname(filename)[1..-1] || '').downcase MARKUP_EXTENSIONS.each do |type, exts| return type if exts.include?(ext) end options.markup end # Strips any shebang lines on the file contents that pertain to # markup or preprocessing data. # # @deprecated Use {CodeObjects::ExtraFileObject#contents} instead # @return [String] the file contents minus any preprocessing tags # @since 0.6.0 def markup_file_contents(contents) contents =~ MARKUP_FILE_SHEBANG ? $' : contents end # Gets the markup provider class/module constant for a markup type # Call {#load_markup_provider} before using this method. # # @param [Symbol] type the markup type (:rdoc, :markdown, etc.) # @return [Class] the markup class def markup_class(type = options.markup) load_markup_provider(type) MarkupHelper.markup_cache[type][:class] end # Gets the markup provider name for a markup type # Call {#load_markup_provider} before using this method. # # @param [Symbol] type the markup type (:rdoc, :markdown, etc.) # @return [Symbol] the markup provider name (usually the gem name of the library) def markup_provider(type = options.markup) MarkupHelper.markup_cache[type][:provider] end end end end yard-0.8.7.3/lib/yard/templates/helpers/filter_helper.rb0000644000004100000410000000125512261240652023177 0ustar www-datawww-datamodule YARD module Templates::Helpers # Helpers for various object types module FilterHelper # @return [Boolean] whether an object is a method def is_method?(object) object.type == :method end # @return [Boolean] whether an object is a namespace def is_namespace?(object) object.is_a?(CodeObjects::NamespaceObject) end # @return [Boolean] whether an object is a class def is_class?(object) object.is_a?(CodeObjects::ClassObject) end # @return [Boolean] whether an object is a module def is_module?(object) object.is_a?(CodeObjects::ModuleObject) end end end end yard-0.8.7.3/lib/yard/templates/helpers/text_helper.rb0000644000004100000410000000660012261240652022675 0ustar www-datawww-datamodule YARD module Templates module Helpers # Helper methods for text template formats. module TextHelper # @return [String] escapes text def h(text) out = "" text = text.split(/\n/) text.each_with_index do |line, i| out << case line when /^\s*$/; "\n\n" when /^\s+\S/, /^=/; line + "\n" else; line + (text[i + 1] =~ /^\s+\S/ ? "\n" : " ") end end out end # @return [String] wraps text at +col+ columns. def wrap(text, col = 72) text.gsub(/(.{1,#{col}})( +|$\n?)|(.{1,#{col}})/, "\\1\\3\n") end # @return [String] indents +text+ by +len+ characters. def indent(text, len = 4) text.gsub(/^/, ' ' * len) end # @return [String] aligns a title to the right def title_align_right(text, col = 72) align_right(text, '-', col) end # @return [String] aligns text to the right def align_right(text, spacer = ' ', col = 72) text = text[0, col - 4] + '...' if (col - 1 - text.length) < 0 spacer * (col - 1 - text.length) + " " + text end # @return [String] returns a horizontal rule for output def hr(col = 72, sep = "-") sep * col end # @return [String] the formatted signature for a method def signature(meth) # use first overload tag if it has a return type and method itself does not if !meth.tag(:return) && meth.tag(:overload) && meth.tag(:overload).tag(:return) meth = meth.tag(:overload) end type = options.default_return || "" rmeth = meth if !rmeth.has_tag?(:return) && rmeth.respond_to?(:object) rmeth = meth.object end if rmeth.tag(:return) && rmeth.tag(:return).types types = rmeth.tags(:return).map {|t| t.types ? t.types : [] }.flatten.uniq first = types.first if types.size == 2 && types.last == 'nil' type = first + '?' elsif types.size == 2 && types.last =~ /^(Array)?<#{Regexp.quote types.first}>$/ type = first + '+' elsif types.size > 2 type = [first, '...'].join(', ') elsif types == ['void'] && options.hide_void_return type = "" else type = types.join(", ") end end type = "(#{type})" if type.include?(',') type = " -> #{type} " unless type.empty? scope = meth.scope == :class ? "#{meth.namespace.name}." : "#{meth.namespace.name.to_s.downcase}." name = meth.name blk = format_block(meth) args = format_args(meth) extras = [] extras_text = '' if rw = meth.namespace.attributes[meth.scope][meth.name] attname = [rw[:read] ? 'read' : nil, rw[:write] ? 'write' : nil].compact attname = attname.size == 1 ? attname.join('') + 'only' : nil extras << attname if attname end extras << meth.visibility if meth.visibility != :public extras_text = '(' + extras.join(", ") + ')' unless extras.empty? title = "%s%s%s %s%s%s" % [scope, name, args, blk, type, extras_text] title.gsub(/\s+/, ' ') end end end end endyard-0.8.7.3/lib/yard/templates/helpers/module_helper.rb0000644000004100000410000000144612261240652023201 0ustar www-datawww-datamodule YARD module Templates module Helpers # Helper methods for managing module objects. module ModuleHelper # Prunes the method listing by running the verifier and removing attributes/aliases # @param [Array] list a list of methods # @param [Boolean] hide_attributes whether to prune attribute methods from the list # @return [Array] a pruned list of methods def prune_method_listing(list, hide_attributes = true) list = run_verifier(list) list = list.reject {|o| o.is_alias? unless CodeObjects::Proxy === o.namespace } list = list.reject {|o| o.is_attribute? unless CodeObjects::Proxy === o.namespace } if hide_attributes list end end end end end yard-0.8.7.3/lib/yard/templates/helpers/method_helper.rb0000644000004100000410000000466212261240652023177 0ustar www-datawww-datamodule YARD module Templates::Helpers # Helper methods for method objects. module MethodHelper # @return [String] formatted arguments for a method def format_args(object) return if object.parameters.nil? params = object.parameters if object.has_tag?(:yield) || object.has_tag?(:yieldparam) params.reject! do |param| param[0].to_s[0,1] == "&" && !object.tags(:param).any? {|t| t.name == param[0][1..-1] } end end unless params.empty? args = params.map do |n, v| v ? "#{n}#{n[-1,1] == ':' ? '' : ' ='} #{v}" : n.to_s end.join(", ") h("(#{args})") else "" end end # @return [String] formatted and linked return types for a method def format_return_types(object) return unless object.has_tag?(:return) && object.tag(:return).types return if object.tag(:return).types.empty? format_types [object.tag(:return).types.first], false end # @return [String] formatted block if one exists def format_block(object) if object.has_tag?(:yield) && object.tag(:yield).types params = object.tag(:yield).types elsif object.has_tag?(:yieldparam) params = object.tags(:yieldparam).map {|t| t.name } elsif object.has_tag?(:yield) return "{ ... }" else params = nil end params ? h("{|" + params.join(", ") + "| ... }") : "" end # @return [String] formats line numbers for source code of an object def format_lines(object) return "" if object.source.nil? || object.line.nil? i = -1 object.source.split(/\n/).map { object.line + (i += 1) }.join("\n") end # @return [String] formats source of an object def format_code(object, show_lines = false) i = -1 lines = object.source.split(/\n/) longestline = (object.line + lines.size).to_s.length lines.map do |line| lineno = object.line + (i += 1) (" " * (longestline - lineno.to_s.length)) + lineno.to_s + " " + line end.join("\n") end # @return [String] formats source code of a constant value def format_constant(value) sp = value.split("\n").last[/^(\s+)/, 1] num = sp ? sp.size : 0 html_syntax_highlight value.gsub(/^\s{#{num}}/, '') end end end end yard-0.8.7.3/lib/yard/templates/template.rb0000644000004100000410000003312612261240652020526 0ustar www-datawww-datarequire 'erb' module YARD module Templates module Template attr_accessor :class, :section attr_reader :options class << self # Extra includes are mixins that are included after a template is created. These # mixins can be registered by plugins to operate on templates and override behaviour. # # Note that this array can be filled with modules or proc objects. If a proc object # is given, the proc will be called with the {Template#options} hash containing # relevant template information like the object, format, and more. The proc should # return a module or nil if there is none. # # @example Adding in extra mixins to include on a template # Template.extra_includes << MyHelper # @example Conditionally including a mixin if the format is html # Template.extra_includes << proc {|opts| MyHelper if opts.format == :html } # @return [Array] a list of modules to be automatically included # into any new template module attr_accessor :extra_includes # @!parse extend ClassMethods # @private def included(klass) klass.extend(ClassMethods) end # Includes the {extra_includes} modules into the template object. # # @param [Template] template the template object to mixin the extra includes. # @param [SymbolHash] options the options hash containing all template information # @return [void] def include_extra(template, options) extra_includes.each do |mod| mod = mod.call(options) if mod.is_a?(Proc) next unless mod.is_a?(Module) template.extend(mod) end end end self.extra_includes = [ proc {|options| { :html => Helpers::HtmlHelper, :text => Helpers::TextHelper, :dot => Helpers::UMLHelper }[options.format] } ] include ErbCache include Helpers::BaseHelper include Helpers::MethodHelper module ClassMethods attr_accessor :path, :full_path # @return [Array] a list of full paths # @note This method caches path results. Paths should not be modified # after this method is called; call {#reset_full_paths} to reset cache. def full_paths reset_full_paths unless defined? @cached_included_modules return @full_paths if included_modules == @cached_included_modules @cached_included_modules = included_modules @full_paths = included_modules.inject([full_path]) do |paths, mod| paths |= mod.full_paths if mod.respond_to?(:full_paths) paths end end # Resets cache for {#full_paths} def reset_full_paths @cached_included_modules = nil end def initialize(path, full_paths) full_path = full_paths.shift self.path = path self.full_path = full_path include_inherited(full_paths) include_parent load_setup_rb end # Searches for a file identified by +basename+ in the template's # path as well as any mixed in template paths. Equivalent to calling # {ClassMethods#find_nth_file} with index of 1. # # @param [String] basename the filename to search for # @return [String] the full path of a file on disk with filename # +basename+ in one of the template's paths. # @see find_nth_file def find_file(basename) find_nth_file(basename) end # Searches for the nth file (where n = +index+) identified # by basename in the template's path and any mixed in template paths. # # @param [String] basename the filename to search for # @param [Fixnum] index the nth existing file to return # @return [String] the full path of the nth file on disk with # filename +basename+ in one of the template paths def find_nth_file(basename, index = 1) n = 1 full_paths.each do |path| file = File.join(path, basename) if File.file?(file) return file if index == n n += 1 end end nil end def is_a?(klass) return true if klass == Template super(klass) end # Creates a new template object to be rendered with {Template#run} def new(*args) obj = Object.new.extend(self) obj.class = self obj.send(:initialize, *args) obj end def run(*args) new(*args).run end def T(*path) Engine.template(*path) end # Alias for creating a {Section} with arguments # @see Section#initialize # @since 0.6.0 def S(*args) Section.new(*args) end private def include_parent pc = path.to_s.split('/') if pc.size > 1 pc.pop pc = pc.join('/') begin include Engine.template(pc) rescue ArgumentError include Engine.template!(pc, full_path.gsub(%r{/[^/]+$}, '')) end end end def include_inherited(full_paths) full_paths.reverse.each do |full_path| include Engine.template!(path, full_path) end end def load_setup_rb setup_file = File.join(full_path, 'setup.rb') if File.file? setup_file module_eval(File.read(setup_file).taint, setup_file, 1) end end end def initialize(opts = TemplateOptions.new) opts_class = opts.class opts_class = TemplateOptions if opts_class == Hash @cache, @cache_filename = {}, {} @sections, @options = [], opts_class.new add_options(opts) Template.include_extra(self, options) init end # Loads a template specified by path. If +:template+ or +:format+ is # specified in the {#options} hash, they are prepended and appended # to the path respectively. # # @param [Array] path the path of the template # @return [Template] the loaded template module def T(*path) path.unshift(options.template) if options.template path.push(options.format) if options.format self.class.T(*path) end # Sets the sections (and subsections) to be rendered for the template # # @example Sets a set of erb sections # sections :a, :b, :c # searches for a.erb, b.erb, c.erb # @example Sets a set of method and erb sections # sections :a, :b, :c # a is a method, the rest are erb files # @example Sections with subsections # sections :header, [:name, :children] # # the above will call header.erb and only renders the subsections # # if they are yielded by the template (see #yieldall) # @param [Array] args the sections # to use to render the template. For symbols and strings, the # section will be executed as a method (if one exists), or rendered # from the file "name.erb" where name is the section name. For # templates, they will have {Template::ClassMethods#run} called on them. # Any subsections can be yielded to using yield or {#yieldall} def sections(*args) @sections = Section.new(nil, *args) if args.size > 0 @sections end # Initialization called on the template. Override this in a 'setup.rb' # file in the template's path to implement a template # # @example A default set of sections # def init # sections :section1, :section2, [:subsection1, :etc] # end # @see #sections def init end # Runs a template on +sects+ using extra options. This method should # not be called directly. Instead, call the class method {ClassMethods#run} # # @param [Hash, nil] opts any extra options to apply to sections # @param [Section, Array] sects a section list of sections to render # @param [Fixnum] start_at the index in the section list to start from # @param [Boolean] break_first if true, renders only the first section # @yield [opts] calls for the subsections to be rendered # @yieldparam [Hash] opts any extra options to yield # @return [String] the rendered sections joined together def run(opts = nil, sects = sections, start_at = 0, break_first = false, &block) out = "" return out if sects.nil? sects = sects[start_at..-1] if start_at > 0 sects = Section.new(nil, sects) unless sects.is_a?(Section) add_options(opts) do sects.each do |s| self.section = s subsection_index = 0 value = render_section(section) do |*args| value = with_section do run(args.first, section, subsection_index, true, &block) end subsection_index += 1 value end out << (value || "") break if break_first end end out end # Yields all subsections with any extra options # # @param [Hash] opts extra options to be applied to subsections def yieldall(opts = nil, &block) with_section { run(opts, section, &block) } end # @param [String, Symbol] section the section name # @yield calls subsections to be rendered # @return [String] the contents of the ERB rendered section def erb(section, &block) method_name = ErbCache.method_for(cache_filename(section)) do erb_with(cache(section), cache_filename(section)) end send(method_name, &block) end # Returns the contents of a file. If +allow_inherited+ is set to +true+, # use +{{{__super__}}}+ inside the file contents to insert the contents # of the file from an inherited template. For instance, if +templates/b+ # inherits from +templates/a+ and file "test.css" exists in both directories, # both file contents can be retrieved by having +templates/b/test.css+ look # like: # # {{{__super__}}} # ... # body { css styles here } # p.class { other styles } # # @param [String] basename the name of the file # @param [Boolean] allow_inherited whether inherited templates can # be inserted with +{{{__super__}}}+ # @return [String] the contents of a file identified by +basename+. All # template paths (including any mixed in templates) are searched for # the file # @see ClassMethods#find_file # @see ClassMethods#find_nth_file def file(basename, allow_inherited = false) file = self.class.find_file(basename) raise ArgumentError, "no file for '#{basename}' in #{self.class.path}" unless file data = IO.read(file) if allow_inherited superfile = self.class.find_nth_file(basename, 2) data.gsub!('{{{__super__}}}', superfile ? IO.read(superfile) : "") end data end # Calls the ERB file from the last inherited template with {#section}.erb # # @param [Symbol, String] section if provided, uses a specific section name # @return [String] the rendered ERB file in any of the inherited template # paths. def superb(section = section, &block) filename = self.class.find_nth_file(erb_file_for(section), 2) return "" unless filename method_name = ErbCache.method_for(filename) { erb_with(IO.read(filename), filename) } send(method_name, &block) end def options=(value) @options = value set_ivars end def inspect "Template(#{self.class.path}) [section=#{section.name}]" end protected def erb_file_for(section) "#{section}.erb" end def erb_with(content, filename = nil) erb = ERB.new(content, nil, options.format == :text ? '<>' : nil) erb.filename = filename if filename erb end private def render_section(section, &block) section = section.name if section.is_a?(Section) case section when Section, String, Symbol if respond_to?(section) send(section, &block) else erb(section, &block) end when Module, Template section.run(options, &block) if section.is_a?(Template) end || "" end def cache(section) content = @cache[section.to_sym] return content if content file = cache_filename(section) @cache_filename[section.to_sym] = file raise ArgumentError, "no template for section '#{section}' in #{self.class.path}" unless file @cache[section.to_sym] = IO.read(file) end def cache_filename(section) @cache_filename[section.to_sym] ||= self.class.find_file(erb_file_for(section)) end def set_ivars options.each do |k, v| instance_variable_set("@#{k}", v) end end def add_options(opts = nil) return(yield) if opts.nil? && block_given? cur_opts = options if block_given? self.options = options.merge(opts) if block_given? value = yield self.options = cur_opts value end end def with_section(&block) sect = section value = yield self.section = sect value end end end end yard-0.8.7.3/lib/yard/rubygems/0000755000004100000410000000000012261240652016220 5ustar www-datawww-datayard-0.8.7.3/lib/yard/rubygems/backports.rb0000644000004100000410000000034212261240652020534 0ustar www-datawww-databegin require 'rubygems' if defined?(Gem::VERSION) && Gem::VERSION >= '1.8.0' require File.dirname(__FILE__) + '/backports/gem' require File.dirname(__FILE__) + '/backports/source_index' end rescue LoadError end yard-0.8.7.3/lib/yard/rubygems/doc_manager.rb0000644000004100000410000000450412261240652021007 0ustar www-datawww-databegin require 'rubygems/user_interaction' require 'rubygems/doc_manager' rescue LoadError end class Gem::DocManager def self.load_yardoc require File.expand_path(File.join(File.dirname(__FILE__), *%w(.. .. yard))) end def run_yardoc(*args) args << '--quiet' args << '--backtrace' if Gem.configuration.backtrace unless File.file?(File.join(@spec.full_gem_path, '.yardopts')) args << @spec.require_paths if @spec.extra_rdoc_files.size > 0 args << '-' args += @spec.extra_rdoc_files end end args = args.flatten.map {|arg| arg.to_s } old_pwd = Dir.pwd Dir.chdir(@spec.full_gem_path) YARD::CLI::Yardoc.run(*args) rescue Errno::EACCES => e dirname = File.dirname e.message.split("-")[1].strip raise Gem::FilePermissionError.new(dirname) rescue => ex alert_error "While generating documentation for #{@spec.full_name}" ui.errs.puts "... MESSAGE: #{ex}" ui.errs.puts "... YARDOC args: #{args.join(' ')}" ui.errs.puts "\t#{ex.backtrace.join("\n\t")}" if Gem.configuration.backtrace ui.errs.puts "(continuing with the rest of the installation)" ensure Dir.chdir(old_pwd) end begin undef setup_rdoc; rescue NameError; end def setup_rdoc if File.exist?(@doc_dir) && !File.writable?(@doc_dir) then raise Gem::FilePermissionError.new(@doc_dir) end FileUtils.mkdir_p @doc_dir unless File.exist?(@doc_dir) self.class.load_rdoc if @spec.has_rdoc? self.class.load_yardoc if @spec.has_yardoc? end def install_yardoc rdoc_dir = File.join(@doc_dir, 'rdoc') FileUtils.rm_rf rdoc_dir say "Installing YARD documentation for #{@spec.full_name}..." run_yardoc '-o', rdoc_dir end def install_ri_yard install_ri_yard_orig if @spec.has_rdoc? return if @spec.has_rdoc? == false return if @spec.has_yardoc? self.class.load_yardoc say "Building YARD (yri) index for #{@spec.full_name}..." run_yardoc '-c', '-n' end begin alias install_ri_yard_orig install_ri alias install_ri install_ri_yard rescue NameError; end def install_rdoc_yard if @spec.has_rdoc? install_rdoc_yard_orig elsif @spec.has_yardoc? install_yardoc end end begin alias install_rdoc_yard_orig install_rdoc alias install_rdoc install_rdoc_yard rescue NameError; end end yard-0.8.7.3/lib/yard/rubygems/backports/0000755000004100000410000000000012261240652020210 5ustar www-datawww-datayard-0.8.7.3/lib/yard/rubygems/backports/LICENSE.txt0000644000004100000410000000463312261240652022041 0ustar www-datawww-dataRubyGems is copyrighted free software by Chad Fowler, Rich Kilmer, Jim Weirich and others. You can redistribute it and/or modify it under either the terms of the MIT license (see the file MIT.txt), or the conditions below: 1. You may make and give away verbatim copies of the source form of the software without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may modify your copy of the software in any way, provided that you do at least ONE of the following: a. place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or by allowing the author to include your modifications in the software. b. use the modified software only within your corporation or organization. c. give non-standard executables non-standard names, with instructions on where to get the original software distribution. d. make other distribution arrangements with the author. 3. You may distribute the software in object code or executable form, provided that you do at least ONE of the following: a. distribute the executables and library files of the software, together with instructions (in the manual page or equivalent) on where to get the original distribution. b. accompany the distribution with the machine-readable source of the software. c. give non-standard executables non-standard names, with instructions on where to get the original software distribution. d. make other distribution arrangements with the author. 4. You may modify and include the part of the software into any other software (possibly commercial). But some files in the distribution are not written by the author, so that they are not under these terms. For the list of those files and their copying conditions, see the file LEGAL. 5. The scripts and library files supplied as input to or produced as output from the software do not automatically fall under the copyright of the software, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this software. 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. yard-0.8.7.3/lib/yard/rubygems/backports/MIT.txt0000644000004100000410000000210012261240652021373 0ustar www-datawww-dataCopyright (c) Chad Fowler, Rich Kilmer, Jim Weirich and others. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. yard-0.8.7.3/lib/yard/rubygems/backports/gem.rb0000644000004100000410000000040212261240652021301 0ustar www-datawww-datamodule Gem class << self undef source_index if method_defined?(:source_index) # Returns the Gem::SourceIndex of specifications that are in the Gem.path def source_index @@source_index ||= SourceIndex.from_installed_gems end end end yard-0.8.7.3/lib/yard/rubygems/backports/source_index.rb0000644000004100000410000002242112261240652023225 0ustar www-datawww-data#-- # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others. # All rights reserved. # See LICENSE.txt for permissions. #++ require 'rubygems/specification' ## # The SourceIndex object indexes all the gems available from a # particular source (e.g. a list of gem directories, or a remote # source). A SourceIndex maps a gem full name to a gem # specification. # # NOTE:: The class used to be named Cache, but that became # confusing when cached source fetchers where introduced. The # constant Gem::Cache is an alias for this class to allow old # YAMLized source index objects to load properly. class Gem::SourceIndex # Undef old methods alias old_initialize initialize undef old_initialize %w(all_gems prerelease_gems load_gems_in latest_specs prerelease_specs released_specs add_spec add_specs remove_spec each specification index_signature gem_signature size length find_name search released_gems refresh! outdated == dump gems spec_dirs spec_dirs=).each do |meth| undef_method(meth) if method_defined?(meth) end include Enumerable attr_reader :gems # :nodoc: ## # Directories to use to refresh this SourceIndex when calling refresh! attr_accessor :spec_dirs class << self # Undef old methods %w(from_installed_gems installed_spec_directories from_gems_in load_specification).each do |meth| if instance_methods(true).find {|m| m.to_s == meth } undef_method(meth) end end ## # Factory method to construct a source index instance for a given # path. # # deprecated:: # If supplied, from_installed_gems will act just like # +from_gems_in+. This argument is deprecated and is provided # just for backwards compatibility, and should not generally # be used. # # return:: # SourceIndex instance def from_installed_gems(*deprecated) if deprecated.empty? from_gems_in(*installed_spec_directories) else from_gems_in(*deprecated) # HACK warn end end ## # Returns a list of directories from Gem.path that contain specifications. def installed_spec_directories Gem.path.collect { |dir| File.join(dir, "specifications") } end ## # Creates a new SourceIndex from the ruby format gem specifications in # +spec_dirs+. def from_gems_in(*spec_dirs) source_index = new source_index.spec_dirs = spec_dirs source_index.refresh! end ## # Loads a ruby-format specification from +file_name+ and returns the # loaded spec. def load_specification(file_name) Gem::Specification.load file_name end end ## # Constructs a source index instance from the provided specifications, which # is a Hash of gem full names and Gem::Specifications. #-- # TODO merge @gems and @prerelease_gems and provide a separate method # #prerelease_gems def initialize(specifications={}) @gems = {} specifications.each{ |full_name, spec| add_spec spec } @spec_dirs = nil end # TODO: remove method def all_gems @gems end def prerelease_gems @gems.reject{ |name, gem| !gem.version.prerelease? } end def released_gems @gems.reject{ |name, gem| gem.version.prerelease? } end ## # Reconstruct the source index from the specifications in +spec_dirs+. def load_gems_in(*spec_dirs) @gems.clear spec_dirs.reverse_each do |spec_dir| spec_files = Dir.glob File.join(spec_dir, '*.gemspec') spec_files.each do |spec_file| gemspec = Gem::Specification.load spec_file add_spec gemspec if gemspec end end self end ## # Returns an Array specifications for the latest released versions # of each gem in this index. def latest_specs(include_prerelease=false) result = Hash.new { |h,k| h[k] = [] } latest = {} sort.each do |_, spec| name = spec.name curr_ver = spec.version prev_ver = latest.key?(name) ? latest[name].version : nil next if !include_prerelease && curr_ver.prerelease? next unless prev_ver.nil? or curr_ver >= prev_ver or latest[name].platform != Gem::Platform::RUBY if prev_ver.nil? or (curr_ver > prev_ver and spec.platform == Gem::Platform::RUBY) then result[name].clear latest[name] = spec end if spec.platform != Gem::Platform::RUBY then result[name].delete_if do |result_spec| result_spec.platform == spec.platform end end result[name] << spec end # TODO: why is this a hash while @gems is an array? Seems like # structural similarity would be good. result.values.flatten end ## # An array including only the prerelease gemspecs def prerelease_specs prerelease_gems.values end ## # An array including only the released gemspecs def released_specs released_gems.values end ## # Add a gem specification to the source index. def add_spec(gem_spec, name = gem_spec.full_name) # No idea why, but the Indexer wants to insert them using original_name # instead of full_name. So we make it an optional arg. @gems[name] = gem_spec end ## # Add gem specifications to the source index. def add_specs(*gem_specs) gem_specs.each do |spec| add_spec spec end end ## # Remove a gem specification named +full_name+. def remove_spec(full_name) @gems.delete full_name end ## # Iterate over the specifications in the source index. def each(&block) # :yields: gem.full_name, gem @gems.each(&block) end ## # The gem specification given a full gem spec name. def specification(full_name) @gems[full_name] end ## # The signature for the source index. Changes in the signature indicate a # change in the index. def index_signature require 'digest' Digest::SHA256.new.hexdigest(@gems.keys.sort.join(',')).to_s end ## # The signature for the given gem specification. def gem_signature(gem_full_name) require 'digest' Digest::SHA256.new.hexdigest(@gems[gem_full_name].to_yaml).to_s end def size @gems.size end alias length size ## # Find a gem by an exact match on the short name. def find_name(gem_name, requirement = Gem::Requirement.default) dep = Gem::Dependency.new gem_name, requirement search dep end ## # Search for a gem by Gem::Dependency +gem_pattern+. If +only_platform+ # is true, only gems matching Gem::Platform.local will be returned. An # Array of matching Gem::Specification objects is returned. # # For backwards compatibility, a String or Regexp pattern may be passed as # +gem_pattern+, and a Gem::Requirement for +platform_only+. This # behavior is deprecated and will be removed. def search(gem_pattern, platform_only = false) requirement = nil only_platform = false # TODO - Remove support and warning for legacy arguments after 2008/11 unless Gem::Dependency === gem_pattern warn "#{Gem.location_of_caller.join ':'}:Warning: Gem::SourceIndex#search support for #{gem_pattern.class} patterns is deprecated, use #find_name" end case gem_pattern when Regexp then requirement = platform_only || Gem::Requirement.default when Gem::Dependency then only_platform = platform_only requirement = gem_pattern.requirement gem_pattern = if Regexp === gem_pattern.name then gem_pattern.name elsif gem_pattern.name.empty? then // else /^#{Regexp.escape gem_pattern.name}$/ end else requirement = platform_only || Gem::Requirement.default gem_pattern = /#{gem_pattern}/i end unless Gem::Requirement === requirement then requirement = Gem::Requirement.create requirement end specs = all_gems.values.select do |spec| spec.name =~ gem_pattern and requirement.satisfied_by? spec.version end if only_platform then specs = specs.select do |spec| Gem::Platform.match spec.platform end end specs.sort_by { |s| s.sort_obj } end ## # Replaces the gems in the source index from specifications in the # directories this source index was created from. Raises an exception if # this source index wasn't created from a directory (via from_gems_in or # from_installed_gems, or having spec_dirs set). def refresh! raise 'source index not created from disk' if @spec_dirs.nil? load_gems_in(*@spec_dirs) end ## # Returns an Array of Gem::Specifications that are not up to date. def outdated outdateds = [] latest_specs.each do |local| dependency = Gem::Dependency.new local.name, ">= #{local.version}" fetcher = Gem::SpecFetcher.fetcher remotes = fetcher.find_matching dependency remotes = remotes.map { |(_, version, _), _| version } latest = remotes.sort.last outdateds << local.name if latest and local.version < latest end outdateds end def ==(other) # :nodoc: self.class === other and @gems == other.gems end def dump Marshal.dump(self) end end # :stopdoc: module Gem ## # Cache is an alias for SourceIndex to allow older YAMLized source index # objects to load properly. Cache = SourceIndex unless defined?(Cache) end # :startdoc: yard-0.8.7.3/lib/yard/rubygems/specification.rb0000644000004100000410000000174612261240652021375 0ustar www-datawww-datarequire 'rubygems/specification' class Gem::Specification # @since 0.5.3 def has_yardoc=(value) @has_rdoc = value ? 'yard' : false end def has_yardoc @has_rdoc == 'yard' end undef has_rdoc? def has_rdoc? (@has_rdoc ||= true) && @has_rdoc != 'yard' end alias has_yardoc? has_yardoc # has_rdoc should not be ignored! if respond_to?(:overwrite_accessor) overwrite_accessor(:has_rdoc) { @has_rdoc ||= true } overwrite_accessor(:has_rdoc=) {|v| @has_rdoc = v } else attr_accessor :has_rdoc end if defined?(Gem::VERSION) && Gem::VERSION >= '1.7.' def _dump_with_rdoc(limit) dmp = _dump_without_rdoc(limit) dmp[15] = @has_rdoc if dmp[15] == true dmp end alias _dump_without_rdoc _dump alias _dump _dump_with_rdoc @@default_value[:has_rdoc] = true if defined?(@@default_value) @@attributes << 'has_rdoc' if defined?(@@attributes) @@nil_attributes << 'has_rdoc' if defined?(@@nil_attributes) end end yard-0.8.7.3/lib/yard/options.rb0000644000004100000410000001744512261240652016416 0ustar www-datawww-datamodule YARD # Generalized options class for passing around large amounts of options between objects. # # The options class exists for better visibility and documentability of options being # passed through to other objects. Because YARD has parser and template architectures # that are heavily reliant on options, it is necessary to make these option keys easily # visible and understood by developers. Since the options class is more than just a # basic Hash, the subclass can provide aliasing and convenience methods to simplify # option property access, and, if needed, support backward-compatibility for deprecated # key names. # # == Hash and OpenStruct-like Access # # Although the options class allows for Hash-like access (opts[:key]), the recommended # mechanism for accessing an option key will be via standard method calls on attributes # # The options class can also act as an open ended key value storage structure (like a # Hash or OpenStruct), and allows for setting and getting of unregistered option keys. # This methodology is not recommended, however, and is only supported for backward # compatibility inside YARD. Whenever possible, developers should define all keys used # by an options class. # # == Declaring Default Values # # Note that the options class can contain default value definitions for certain options, # but to initialize these defaults, {#reset_defaults} must be called manually after # initialization; the options object is always created empty until defaults are applied. # # @abstract Subclasses should define (and document) custom attributes that are expected # to be made available as option keys. # @example Defining an Options class with custom option keys # class TemplateOptions < YARD::Options # # @return [Symbol] the output format to generate templates in # attr_accessor :format # # # @return [Symbol] the template to use when generating output # attr_accessor :template # end # @example Initializing default option values # class TemplateOptions < YARD::Options # def reset_defaults # super # self.format = :html # self.template = :default # self.highlight = true # # ... # end # end # @example Using +default_attr+ to create default attributes # class TemplateOptions < YARD::Options # default_attr :format, :html # default_attr :template, :default # default_attr :highlight, true # end # @example Deprecating an option while still supporting it # class TemplateOptions < YARD::Options # # @return [Boolean] if syntax highlighting should be performed on code blocks. # # Defaults to true. # attr_accessor :highlight # # # @deprecated Use {#highlight} instead. # # @return [Boolean] if no syntax highlighting should be performs on code blocks. # # Defaults to false. # attr_accessor :no_highlight # def no_highlight=(value) @highlight = !value end # def no_highlight; !highlight end # end class Options # @!macro [attach] yard.default_attr # @!attribute $1 # Defines an attribute named +key+ and sets a default value for it # # @example Defining a default option key # default_attr :name, 'Default Name' # default_attr :time, lambda { Time.now } # @param [Symbol] key the option key name # @param [Object, Proc] default the default object value. If the default # value is a proc, it is executed upon initialization. def self.default_attr(key, default) (@defaults ||= {})[key] = default attr_accessor(key) end # Delegates calls with Hash syntax to actual method with key name # # @example Calling on an option key with Hash syntax # options[:format] # equivalent to: options.format # @param [Symbol, String] key the option name to access # @return the value of the option named +key+ def [](key) send(key) end # Delegates setter calls with Hash syntax to the attribute setter with the key name # # @example Setting an option with Hash syntax # options[:format] = :html # equivalent to: options.format = :html # @param [Symbol, String] key the optin to set # @param [Object] value the value to set for the option # @return [Object] the value being set def []=(key, value) send("#{key}=", value) end # Updates values from an options hash or options object on this object. # All keys passed should be key names defined by attributes on the class. # # @example Updating a set of options on an Options object # opts.update(:template => :guide, :type => :fulldoc) # @param [Hash, Options] opts # @return [self] def update(opts) opts = opts.to_hash if Options === opts opts.each do |key, value| self[key] = value end self end # Creates a new options object and sets options hash or object value # onto that object. # # @param [Options, Hash] opts # @return [Options] the newly created options object # @see #update def merge(opts) dup.update(opts) end # @return [Hash] Converts options object to an options hash. All keys # will be symbolized. def to_hash opts = {} instance_variables.each do |ivar| name = ivar.to_s.sub(/^@/, '') opts[name.to_sym] = send(name) end opts end # Yields over every option key and value # @yield [key, value] every option key and value # @yieldparam [Symbol] key the option key # @yieldparam [Object] value the option value # @return [void] def each(&block) instance_variables.each do |ivar| name = ivar.to_s.sub(/^@/, '') yield(name.to_sym, send(name)) end end # Inspects the object def inspect "<#{self.class}: #{to_hash.inspect}>" end # @return [Boolean] whether another Options object equals the # keys and values of this options object def ==(other) case other when Options; to_hash == other.to_hash when Hash; to_hash == other else false end end # Handles setting and accessing of unregistered keys similar # to an OpenStruct object. # # @note It is not recommended to set and access unregistered keys on # an Options object. Instead, register the attribute before using it. def method_missing(meth, *args, &block) if meth.to_s =~ /^(.+)=$/ log.debug "Attempting to set unregistered key #{$1} on #{self.class}" instance_variable_set("@#{$1}", args.first) elsif args.size == 0 log.debug "Attempting to access unregistered key #{meth} on #{self.class}" instance_variable_get("@#{meth}") else super end end # Resets all values to their defaults. # # @abstract Subclasses should override this method to perform custom # value initialization if not using {default_attr}. Be sure to call # +super+ so that default initialization can take place. # @return [void] def reset_defaults names_set = {} self.class.ancestors.each do |klass| # look at all ancestors defaults = klass.instance_variable_get("@defaults") next unless defaults defaults.each do |key, value| next if names_set[key] names_set[key] = true self[key] = Proc === value ? value.call : value end end end # Deletes an option value for +key+ # # @param [Symbol, String] key the key to delete a value for # @return [Object] the value that was deleted def delete(key) val = self[key] if instance_variable_defined?("@#{key}") remove_instance_variable("@#{key}") end val end unless defined? tap() # only for 1.8.6 def tap(&block) yield(self); self end end end end yard-0.8.7.3/lib/yard/rake/0000755000004100000410000000000012261240652015305 5ustar www-datawww-datayard-0.8.7.3/lib/yard/rake/yardoc_task.rb0000644000004100000410000000444112261240652020140 0ustar www-datawww-datarequire 'rake' require 'rake/tasklib' module YARD module Rake # The rake task to run {CLI::Yardoc} and generate documentation. class YardocTask < ::Rake::TaskLib # The name of the task # @return [String] the task name attr_accessor :name # Options to pass to {CLI::Yardoc} # @return [Array] the options passed to the commandline utility attr_accessor :options # The Ruby source files (and any extra documentation files separated by '-') # to process. # @example Task files assignment # YARD::Rake::YardocTask.new do |t| # t.files = ['app/**/*.rb', 'lib/**/*.rb', '-', 'doc/FAQ.md', 'doc/Changes.md'] # end # @return [Array] a list of files attr_accessor :files # Runs a +Proc+ before the task # @return [Proc] a proc to call before running the task attr_accessor :before # Runs a +Proc+ after the task # @return [Proc] a proc to call after running the task attr_accessor :after # @return [Verifier, Proc] an optional {Verifier} to run against all objects # being generated. Any object that the verifier returns false for will be # excluded from documentation. This attribute can also be a lambda. # @see Verifier attr_accessor :verifier # Creates a new task with name +name+. # # @param [String, Symbol] name the name of the rake task # @yield a block to allow any options to be modified on the task # @yieldparam [YardocTask] _self the task object to allow any parameters # to be changed. def initialize(name = :yard) @name = name @options = [] @files = [] yield self if block_given? self.options += ENV['OPTS'].split(/[ ,]/) if ENV['OPTS'] self.files += ENV['FILES'].split(/[ ,]/) if ENV['FILES'] define end protected # Defines the rake task # @return [void] def define desc "Generate YARD Documentation" task(name) do before.call if before.is_a?(Proc) yardoc = YARD::CLI::Yardoc.new yardoc.options[:verifier] = verifier if verifier yardoc.run *(options + files) after.call if after.is_a?(Proc) end end end end endyard-0.8.7.3/lib/yard/verifier.rb0000644000004100000410000001133312261240652016524 0ustar www-datawww-datamodule YARD # Similar to a Proc, but runs a set of Ruby expressions using a small # DSL to make tag lookups easier. # # The syntax is as follows: # * All syntax is Ruby compatible # * +object+ (+o+ for short) exist to access the object being verified # * +@TAGNAME+ is translated into +object.tag('TAGNAME')+ # * +@@TAGNAME+ is translated into +object.tags('TAGNAME')+ # * +object+ can be omitted as target for method calls (it is implied) # # @example Create a verifier to check for objects that don't have @private tags # verifier = Verifier.new('!@private') # verifier.call(object) # => true (no @private tag) # @example Create a verifier to find any return tag with an empty description # Verifier.new('@return.text.empty?') # # Equivalent to: # Verifier.new('object.tag(:return).text.empty?') # @example Check if there are any @param tags # Verifier.new('@@param.empty?') # # Equivalent to: # Verifier.new('object.tags(:param).empty?') # @example Using +object+ or +o+ to look up object attributes directly # Verifier.new('object.docstring == "hello world"') # # Equivalent to: # Verifier.new('o.docstring == "hello world"') # @example Without using +object+ or +o+ # Verifier.new('tag(:return).size == 1 || has_tag?(:author)') # @example Specifying multiple expressions # Verifier.new('@return', '@param', '@yield') # # Equivalent to: # Verifier.new('@return && @param && @yield') class Verifier # @return [Array] a list of all expressions the verifier checks for # @since 0.5.6 attr_reader :expressions def expressions=(value) @expressions = value create_method_from_expressions end # Creates a verifier from a set of expressions # # @param [Array] expressions a list of Ruby expressions to # parse. def initialize(*expressions) @expressions = [] add_expressions(*expressions) end # Adds a set of expressions and recompiles the verifier # # @param [Array] expressions a list of expressions # @return [void] # @since 0.5.6 def add_expressions(*expressions) self.expressions += expressions.flatten end # Passes any method calls to the object from the {#call} def method_missing(sym, *args, &block) if object.respond_to?(sym) object.send(sym, *args, &block) else super end end # Tests the expressions on the object. # # @note If the object is a {CodeObjects::Proxy} the result will always be true. # @param [CodeObjects::Base] object the object to verify # @return [Boolean] the result of the expressions def call(object) return true if object.is_a?(CodeObjects::Proxy) modify_nilclass @object = object retval = __execute ? true : false unmodify_nilclass retval end # Runs a list of objects against the verifier and returns the subset # of verified objects. # # @param [Array] list a list of code objects # @return [Array] a list of code objects that match # the verifier. def run(list) list.reject {|item| call(item).is_a?(FalseClass) } end protected # @return [CodeObjects::Base] the current object being tested attr_reader :object alias o object private # @private NILCLASS_METHODS = [:type, :method_missing] # Modifies nil to not throw NoMethodErrors. This allows # syntax like object.tag(:return).text to work if the #tag # call returns nil, which means users don't need to perform # stringent nil checking # # @return [void] def modify_nilclass NILCLASS_METHODS.each do |meth| NilClass.send(:define_method, meth) {|*args| } end end # Returns the state of NilClass back to normal # @return [void] def unmodify_nilclass NILCLASS_METHODS.each do |meth| NilClass.send(:remove_method, meth) end end # Creates the +__execute+ method by evaluating the expressions # as Ruby code # @return [void] def create_method_from_expressions expr = expressions.map {|e| "(#{parse_expression(e)})" }.join(" && ") instance_eval(<<-eof, __FILE__, __LINE__ + 1) def __execute; #{expr}; end eof end # Parses a single expression, handling some of the DSL syntax. # # The syntax "@tag" should be turned into object.tag(:tag), # and "@@tag" should be turned into object.tags(:tag) # # @return [String] the parsed expression def parse_expression(expr) expr = expr.gsub(/@@(?:(\w+)|\{([\w\.]+)\})/, 'object.tags("\1\2")') expr = expr.gsub(/@(?:(\w+)|\{([\w\.]+)\})/, 'object.tag("\1\2")') expr end end end yard-0.8.7.3/lib/yard/server/0000755000004100000410000000000012261240652015671 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/doc_server_helper.rb0000644000004100000410000000615212261240652021714 0ustar www-datawww-datamodule YARD module Server # A module that is mixed into {Templates::Template} in order to customize # certain template methods. module DocServerHelper # Modifies {Templates::Helpers::HtmlHelper#url_for} to return a URL instead # of a disk location. # @param (see Templates::Helpers::HtmlHelper#url_for) # @return (see Templates::Helpers::HtmlHelper#url_for) def url_for(obj, anchor = nil, relative = false) return '' if obj.nil? return url_for_index if obj == '_index.html' return "/#{obj}" if String === obj url = super(obj, anchor, false) return unless url File.join('', base_path(router.docs_prefix), url) end # Modifies {Templates::Helpers::HtmlHelper#url_for_file} to return a URL instead # of a disk location. # @param (see Templates::Helpers::HtmlHelper#url_for_file) # @return (see Templates::Helpers::HtmlHelper#url_for_file) def url_for_file(filename, anchor = nil) if filename.is_a?(CodeObjects::ExtraFileObject) filename = filename.filename end "/#{base_path(router.docs_prefix)}/file/" + filename.sub(%r{^#{@library.source_path.to_s}/}, '') + (anchor ? "##{anchor}" : "") end # Modifies {Templates::Helpers::HtmlHelper#url_for_list} to return a URL # based on the list prefix instead of a HTML filename. # @param (see Templates::Helpers::HtmlHelper#url_for_list) # @return (see Templates::Helpers::HtmlHelper#url_for_list) def url_for_list(type) File.join('', base_path(router.list_prefix), type.to_s) end # Returns the frames URL for the page # @return (see Templates::Helpers::HtmlHelper#url_for_frameset) def url_for_frameset url = options.file ? url_for_file(options.file) : url_for(object) url = url.gsub(%r{^/#{base_path(router.docs_prefix)}/}, '') File.join('', base_path(router.docs_prefix), "frames", url) end # Returns the main URL, first checking a readme and then linking to the index # @return (see Templates::Helpers::HtmlHelper#url_for_main) def url_for_main if options.frames && !options.command.path.empty? File.join('', base_path(router.docs_prefix), options.command.path) else options.readme ? url_for_file(options.readme) : url_for_index end end # Returns the URL for the alphabetic index page # @return (see Templates::Helpers::HtmlHelper#url_for_index) def url_for_index File.join('', base_path(router.docs_prefix), 'index') end # @example The base path for a library 'foo' # base_path('docs') # => 'docs/foo' # @param [String] path the path prefix for a base path URI # @return [String] the base URI for a library with an extra +path+ prefix def base_path(path) libname = router.request.version_supplied ? @library.to_s : @library.name path + (@single_library ? '' : "/#{libname}") end # @return [Router] convenience method for accessing the router def router; @adapter.router end end end end yard-0.8.7.3/lib/yard/server/static_caching.rb0000644000004100000410000000334012261240652021161 0ustar www-datawww-datamodule YARD module Server # Implements static caching for requests. # # @see Router Router documentation for "Caching" module StaticCaching # Called by a router to return the cached object. By default, this # method performs disk-based caching. To perform other forms of caching, # implement your own +#check_static_cache+ method and mix the module into # the Router class. # # Note that caching does not occur here. This method simply checks for # the existence of cached data. To actually cache a response, see # {Commands::Base#cache}. # # @example Implementing In-Memory Cache Checking # module MemoryCaching # def check_static_cache # # $memory_cache is filled by {Commands::Base#cache} # cached_data = $memory_cache[request.path] # if cached_data # [200, {'Content-Type' => 'text/html'}, [cached_data]] # else # nil # end # end # end # # class YARD::Server::Router; include MemoryCaching; end # @return [Array(Numeric,Hash,Array)] the Rack-style response # @return [nil] if no cache is available and routing should continue # @see Commands::Base#cache def check_static_cache return nil unless adapter.document_root cache_path = File.join(adapter.document_root, request.path.sub(/\.html$/, '') + '.html') cache_path = cache_path.sub(%r{/\.html$}, '.html') if File.file?(cache_path) log.debug "Loading cache from disk: #{cache_path}" return [200, {'Content-Type' => 'text/html'}, [File.read_binary(cache_path)]] end nil end end end end yard-0.8.7.3/lib/yard/server/router.rb0000644000004100000410000001434612261240652017546 0ustar www-datawww-datamodule YARD module Server # A router class implements the logic used to recognize a request for a specific # URL and run specific {Commands::Base commands}. # # == Subclassing Notes # To create a custom router, subclass this class and pass it into the adapter # options through {Adapter#initialize} or by directly modifying {Adapter#router}. # # The most general customization is to change the URL prefixes recognized by # routing, which can be done by overriding {#docs_prefix}, {#list_prefix} # and {#search_prefix}. # # == Implementing Custom Caching # By default, the Router class performs static disk-based caching on all # requests through the +#check_static_cache+. To override this behaviour, # or create your own caching mechanism, mixin your own custom module with # this method implemented as per {StaticCaching#check_static_cache}. # # @example Creating a subclassed router # # Adds 'my' to all routing prefixes # class MyRouter < YARD::Server::Router # def docs_prefix; 'mydocs' end # def list_prefix; 'mylist' end # def search_prefix; 'mysearch' end # end # # # Using it: # WebrickAdapter.new(libraries, :router => MyRouter).start class Router include StaticCaching include Commands # @return [Adapter Dependent] the request data coming in with the routing attr_accessor :request # @return [Adapter] the adapter used by the router attr_accessor :adapter # Creates a new router for a specific adapter # # @param [Adapter] adapter the adapter to route requests to def initialize(adapter) self.adapter = adapter end # Perform routing on a specific request, serving the request as a static # file through {Commands::StaticFileCommand} if no route is found. # # @param [Adapter Dependent] request the request object # @return [Array(Numeric,Hash,Array)] the Rack-style server response data def call(request) self.request = request if result = (check_static_cache || route) result else StaticFileCommand.new(adapter.options).call(request) end end # @group Route Prefixes # @return [String] the URI prefix for all object documentation requests def docs_prefix; 'docs' end # @return [String] the URI prefix for all class/method/file list requests def list_prefix; 'list' end # @return [String] the URI prefix for all search requests def search_prefix; 'search' end # @group Routing Methods # @return [Array(LibraryVersion, Array)] the library followed # by the rest of the path components in the request path. LibraryVersion # will be nil if no matching library was found. def parse_library_from_path(paths) return [adapter.libraries.values.first.first, paths] if adapter.options[:single_library] library, paths = nil, paths.dup if libs = adapter.libraries[paths.first] paths.shift if library = libs.find {|l| l.version == paths.first } request.version_supplied = true if request paths.shift else # use the last lib in the list request.version_supplied = false if request library = libs.last end end [library, paths] end protected # Performs routing algorithm to find which prefix is called, first # parsing out library name/version information. # # @return [Array(Numeric,Hash,Array)] the Rack-style response # @return [nil] if no route is matched def route(path = request.path) path = path.gsub(%r{//+}, '/').gsub(%r{^/|/$}, '') return route_index if path.empty? || path == docs_prefix case path when /^(#{docs_prefix}|#{list_prefix}|#{search_prefix})(\/.*|$)/ prefix = $1 paths = $2.gsub(%r{^/|/$}, '').split('/') library, paths = *parse_library_from_path(paths) return unless library return case prefix when docs_prefix; route_docs(library, paths) when list_prefix; route_list(library, paths) when search_prefix; route_search(library, paths) end end nil end # Routes requests from {#docs_prefix} and calls the appropriate command # @param [LibraryVersion] library the library to route for # @param [Array] paths path components (split by '/') # @return (see #route) def route_docs(library, paths) return route_index if library.nil? case paths.first when "frames" paths.shift cmd = FramesCommand when "file" paths.shift cmd = DisplayFileCommand else cmd = DisplayObjectCommand end cmd = cmd.new(final_options(library, paths)) cmd.call(request) end # Routes for the index of a library / multiple libraries # @return (see #route) def route_index if adapter.options[:single_library] route_docs(adapter.libraries.values.first.first, []) else LibraryIndexCommand.new(adapter.options.merge(:path => '')).call(request) end end # Routes requests from {#list_prefix} and calls the appropriate command # @param (see #route_docs) # @return (see #route_docs) def route_list(library, paths) return if paths.empty? ListCommand.new(final_options(library, paths)).call(request) end # Routes requests from {#search_prefix} and calls the appropriate command # @param (see #route_docs) # @return (see #route_docs) def route_search(library, paths) return unless paths.empty? SearchCommand.new(final_options(library, paths)).call(request) end # @group Utility Methods # Adds extra :library/:path option keys to the adapter options. # Use this method when passing options to a command. # # @param (see #route_docs) # @return [Hash] finalized options def final_options(library, paths) adapter.options.merge(:library => library, :path => paths.join('/')) end end end end yard-0.8.7.3/lib/yard/server/doc_server_serializer.rb0000644000004100000410000000245712261240652022612 0ustar www-datawww-datarequire 'webrick/httputils' module YARD module Server # A custom {Serializers::Base serializer} which returns resource URLs instead of # static relative paths to files on disk. class DocServerSerializer < Serializers::FileSystemSerializer include WEBrick::HTTPUtils def initialize(command = nil) super(:basepath => '', :extension => '') end def serialized_path(object) case object when CodeObjects::RootObject "toplevel" when CodeObjects::ExtendedMethodObject name = object.name.to_s serialized_path(object.namespace) + ':' + urlencode(object.name.to_s) when CodeObjects::MethodObject serialized_path(object.namespace) + (object.scope == :instance ? ":" : ".") + urlencode(object.name.to_s) when CodeObjects::ConstantObject, CodeObjects::ClassVariableObject serialized_path(object.namespace) + "##{object.name}-#{object.type}" when CodeObjects::ExtraFileObject super(object).gsub(/^file\./, 'file/') else super(object) end end private def urlencode(name) if name.respond_to?(:force_encoding) name = name.dup.force_encoding('binary') end escape(name) end end end end yard-0.8.7.3/lib/yard/server/commands/0000755000004100000410000000000012261240652017472 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/commands/list_command.rb0000644000004100000410000000116712261240652022475 0ustar www-datawww-datamodule YARD module Server module Commands # Returns a list of objects of a specific type class ListCommand < LibraryCommand include Templates::Helpers::BaseHelper def run Registry.load_all options.update(:objects => run_verifier(Registry.all(:class, :module))) list_type = request.path.split('/').last meth = "generate_#{list_type}_list" tpl = fulldoc_template if tpl.respond_to?(meth) tpl.send(meth) cache(tpl.contents) else not_found end end end end end end yard-0.8.7.3/lib/yard/server/commands/display_object_command.rb0000644000004100000410000000265112261240652024514 0ustar www-datawww-datamodule YARD module Server module Commands # Displays documentation for a specific object identified by the path class DisplayObjectCommand < LibraryCommand include DocServerHelper def run if path.empty? if options.readme url = url_for_file(options.readme) self.status, self.headers, self.body = *router.send(:route, url) cache(body.first) return else self.path = 'index' end end return index if path == 'index' if object = Registry.at(object_path) options.update(:type => :layout) render(object) else self.status = 404 end end def index Registry.load_all options.update( :object => '_index.html', :objects => Registry.all(:module, :class), :type => :layout ) render end def not_found super self.body = "Could not find object: #{object_path}" end private def object_path return @object_path if @object_path if path == "toplevel" @object_path = :root else @object_path = path.sub(':', '#').gsub('/', '::').sub(/^toplevel\b/, '').sub(/\.html$/, '') end end end end end end yard-0.8.7.3/lib/yard/server/commands/frames_command.rb0000644000004100000410000000054212261240652022773 0ustar www-datawww-datamodule YARD module Server module Commands # Displays an object wrapped in frames class FramesCommand < DisplayObjectCommand def run options.update(:frames => true, :type => :fulldoc) tpl = fulldoc_template tpl.generate_frameset cache(tpl.contents) end end end end end yard-0.8.7.3/lib/yard/server/commands/library_index_command.rb0000644000004100000410000000106712261240652024354 0ustar www-datawww-datamodule YARD module Server module Commands # Returns the index of libraries served by the server. class LibraryIndexCommand < Base attr_accessor :options def run return unless path.empty? self.options = SymbolHash.new(false).update( :markup => :rdoc, :format => :html, :libraries => adapter.libraries, :adapter => adapter, :template => :doc_server, :type => :library_list ) render end end end end endyard-0.8.7.3/lib/yard/server/commands/static_file_command.rb0000644000004100000410000000337112261240652024007 0ustar www-datawww-datarequire 'webrick/httputils' module YARD module Server module Commands # Serves static content when no other router matches a request class StaticFileCommand < Base include WEBrick::HTTPUtils DefaultMimeTypes['js'] = 'text/javascript' # Defines the paths used to search for static assets. To define an # extra path, use {YARD::Server.register_static_path} rather than # modifying this constant directly. Also note that files in the # document root will always take precedence over these paths. STATIC_PATHS = [] def run assets_template = Templates::Engine.template(:default, :fulldoc, :html) path = File.cleanpath(request.path).gsub(%r{^(../)+}, '') file = nil ([adapter.document_root] + STATIC_PATHS.reverse).compact.each do |path_prefix| file = File.join(path_prefix, path) break if File.exist?(file) file = nil end # Search in default/fulldoc/html template if nothing in static asset paths file ||= assets_template.find_file(path) if file ext = "." + (request.path[/\.(\w+)$/, 1] || "html") headers['Content-Type'] = mime_type(ext, DefaultMimeTypes) self.body = File.read(file) return end favicon? self.status = 404 end private # Return an empty favicon.ico if it does not exist so that # browsers don't complain. def favicon? return unless request.path == '/favicon.ico' self.headers['Content-Type'] = 'image/png' self.status = 200 self.body = '' raise FinishRequest end end end end endyard-0.8.7.3/lib/yard/server/commands/display_file_command.rb0000644000004100000410000000147712261240652024172 0ustar www-datawww-datamodule YARD module Server module Commands # Displays a README or extra file. # # @todo Implement better support for detecting binary (image) filetypes class DisplayFileCommand < LibraryCommand def run ppath = library.source_path filename = File.cleanpath(File.join(library.source_path, path)) raise NotFoundError if !File.file?(filename) if filename =~ /\.(jpe?g|gif|png|bmp)$/i headers['Content-Type'] = StaticFileCommand::DefaultMimeTypes[$1.downcase] || 'text/html' render IO.read(filename) else file = CodeObjects::ExtraFileObject.new(filename) options.update(:object => Registry.root, :type => :layout, :file => file) render end end end end end endyard-0.8.7.3/lib/yard/server/commands/base.rb0000644000004100000410000001520712261240652020736 0ustar www-datawww-datarequire 'fileutils' module YARD module Server module Commands # This is the base command class used to implement custom commands for # a server. A command will be routed to by the {Router} class and return # a Rack-style response. # # == Attribute Initializers # All attributes can be initialized via options passed into the {#initialize} # method. When creating a custom command, the {Adapter#options} will # automatically be mapped to attributes by the same name on your class. # # class MyCommand < Base # attr_accessor :myattr # end # # Adapter.new(libs, {:myattr => 'foo'}).start # # # when a request comes in, cmd.myattr == 'foo' # # == Subclassing Notes # To implement a custom command, override the {#run} method, not {#call}. # In your implementation, you should set the body and status for requests. # See details in the +#run+ method documentation. # # Note that if your command deals directly with libraries, you should # consider subclassing the more specific {LibraryCommand} class instead. # # @abstract # @see #run class Base # @group Basic Command and Adapter Options # @return [Hash] the options passed to the command's constructor attr_accessor :command_options # @return [Adapter] the server adapter attr_accessor :adapter # @return [Boolean] whether to cache attr_accessor :caching # @group Attributes Set Per Request # @return [Request] request object attr_accessor :request # @return [String] the path after the command base URI attr_accessor :path # @return [Hash{String => String}] response headers attr_accessor :headers # @return [Numeric] status code. Defaults to 200 per request attr_accessor :status # @return [String] the response body. Defaults to empty string. attr_accessor :body # @group Instance Method Summary # Creates a new command object, setting attributes named by keys # in the options hash. After initialization, the options hash # is saved in {#command_options} for further inspection. # # @example Creating a Command # cmd = DisplayObjectCommand.new(:caching => true, :library => mylib) # cmd.library # => mylib # cmd.command_options # => {:caching => true, :library => mylib} # @param [Hash] opts the options hash, saved to {#command_options} # after initialization. def initialize(opts = {}) opts.each do |key, value| send("#{key}=", value) if respond_to?("#{key}=") end self.command_options = opts end # The main method called by a router with a request object. # # @note This command should not be overridden by subclasses. Implement # the callback method {#run} instead. # @param [Adapter Dependent] request the request object # @return [Array(Numeric,Hash,Array)] a Rack-style response # of status, headers, and body wrapped in an array. def call(request) self.request = request self.path ||= request.path[1..-1] self.headers = {'Content-Type' => 'text/html'} self.body = '' self.status = 200 begin run rescue FinishRequest rescue NotFoundError => e self.body = e.message if e.message != e.class.to_s self.status = 404 end not_found if status == 404 [status, headers, body.is_a?(Array) ? body : [body]] end # @group Abstract Methods # Subclass this method to implement a custom command. This method # should set the {#status} and {#body}, and optionally modify the # {#headers}. Note that +#status+ defaults to 200. # # @example A custom command # class ErrorCommand < Base # def run # self.body = 'ERROR! The System is down!' # self.status = 500 # self.headers['Conten-Type'] = 'text/plain' # end # end # # @abstract # @return [void] def run raise NotImplementedError end protected # @group Helper Methods # Renders a specific object if provided, or a regular template rendering # if object is not provided. # # @todo This method is dependent on +#options+, it should be in {LibraryCommand}. # @param [CodeObjects::Base, nil] object calls {CodeObjects::Base#format} if # an object is provided, or {Templates::Engine.render} if object is nil. Both # receive +#options+ as an argument. # @return [String] the resulting output to display def render(object = nil) case object when CodeObjects::Base cache object.format(options) when nil cache Templates::Engine.render(options) else cache object end end # Override this method to implement custom caching mechanisms for # # @example Caching to memory # $memory_cache = {} # def cache(data) # $memory_cache[path] = data # end # @param [String] data the data to cache # @return [String] the same cached data (for chaining) # @see StaticCaching def cache(data) if caching && adapter.document_root path = File.join(adapter.document_root, request.path.sub(/\.html$/, '') + '.html') path = path.sub(%r{/\.html$}, '.html') FileUtils.mkdir_p(File.dirname(path)) log.debug "Caching data to #{path}" File.open(path, 'wb') {|f| f.write(data) } end self.body = data end # Sets the body and headers (but not status) for a 404 response. Does # nothing if the body is already set. # # @return [void] def not_found return unless body.empty? self.body = "Not found: #{request.path}" self.headers['Content-Type'] = 'text/plain' self.headers['X-Cascade'] = 'pass' end # Sets the headers and status code for a redirection to a given URL # @param [String] url the URL to redirect to # @raise [FinishRequest] causes the request to terminate. def redirect(url) headers['Location'] = url self.status = 302 raise FinishRequest end end end end end yard-0.8.7.3/lib/yard/server/commands/library_command.rb0000644000004100000410000001124412261240652023163 0ustar www-datawww-datarequire 'thread' module YARD module Server module Commands class LibraryOptions < CLI::YardocOptions def adapter; @command.adapter end def library; @command.library end def single_library; @command.single_library end def serializer; @command.serializer end def serialize; false end attr_accessor :command attr_accessor :frames def each(&block) super(&block) yield(:adapter, adapter) yield(:library, library) yield(:single_library, single_library) yield(:serializer, serializer) end end # This is the base command for all commands that deal directly with libraries. # Some commands do not, but most (like {DisplayObjectCommand}) do. If your # command deals with libraries directly, subclass this class instead. # See {Base} for notes on how to subclass a command. # # @abstract class LibraryCommand < Base # @return [LibraryVersion] the object containing library information attr_accessor :library # @return [LibraryOptions] default options for the library attr_accessor :options # @return [Serializers::Base] the serializer used to perform file linking attr_accessor :serializer # @return [Boolean] whether router should route for multiple libraries attr_accessor :single_library # @return [Boolean] whether to reparse data attr_accessor :incremental # Needed to synchronize threads in {#setup_yardopts} # @private @@library_chdir_lock = Mutex.new def initialize(opts = {}) super self.serializer = DocServerSerializer.new end def call(request) save_default_template_info self.request = request self.options = LibraryOptions.new self.options.reset_defaults self.options.command = self setup_library self.options.title = "Documentation for #{library.name} " + (library.version ? '(' + library.version + ')' : '') super rescue LibraryNotPreparedError not_prepared ensure restore_template_info end private def save_default_template_info @old_template_paths = Templates::Engine.template_paths.dup @old_extra_includes = Templates::Template.extra_includes.dup end def restore_template_info Templates::Engine.template_paths = @old_template_paths Templates::Template.extra_includes = @old_extra_includes end def setup_library library.prepare! if request.xhr? && request.query['process'] load_yardoc setup_yardopts true end def setup_yardopts @@library_chdir_lock.synchronize do Dir.chdir(library.source_path) do yardoc = CLI::Yardoc.new if incremental yardoc.run('-c', '-n', '--no-stats') else yardoc.parse_arguments end yardoc.send(:verify_markup_options) yardoc.options.delete(:serializer) yardoc.options.delete(:serialize) options.update(yardoc.options.to_hash) end end end def load_yardoc raise LibraryNotPreparedError unless library.yardoc_file if Thread.current[:__yard_last_yardoc__] == library.yardoc_file log.debug "Reusing yardoc file: #{library.yardoc_file}" return end Registry.clear Templates::ErbCache.clear! Registry.load_yardoc(library.yardoc_file) Thread.current[:__yard_last_yardoc__] = library.yardoc_file end def not_prepared self.caching = false options.update(:template => :doc_server, :type => :processing) [202, {'Content-Type' => 'text/html'}, [render]] end # Hack to load a custom fulldoc template object that does # not do any rendering/generation. We need this to access the # generate_*_list methods. def fulldoc_template tplopts = [options.template, :fulldoc, options.format] tplclass = Templates::Engine.template(*tplopts) obj = Object.new.extend(tplclass) class << obj; def init; end end obj.class = tplclass obj.send(:initialize, options) class << obj attr_reader :contents def asset(file, contents) @contents = contents end end obj end # @private @@last_yardoc = nil end end end end yard-0.8.7.3/lib/yard/server/commands/search_command.rb0000644000004100000410000000464212261240652022770 0ustar www-datawww-datamodule YARD module Server module Commands # Performs a search over the objects inside of a library and returns # the results as HTML or plaintext class SearchCommand < LibraryCommand include Templates::Helpers::BaseHelper include Templates::Helpers::ModuleHelper include DocServerHelper attr_accessor :results, :query def run Registry.load_all self.query = request.query['q'] redirect("/#{adapter.router.docs_prefix}/#{single_library ? library : ''}") if query.nil? || query =~ /\A\s*\Z/ if found = Registry.at(query) redirect(url_for(found)) end search_for_object request.xhr? ? serve_xhr : serve_normal end def visible_results results[0, 10] end private def url_for(object) File.join('', base_path(router.docs_prefix), serializer.serialized_path(object)) end def serve_xhr self.headers['Content-Type'] = 'text/plain' self.body = visible_results.map {|o| [(o.type == :method ? o.name(true) : o.name).to_s, o.path, o.namespace.root? ? '' : o.namespace.path, url_for(o) ].join(",") }.join("\n") end def serve_normal options.update( :visible_results => visible_results, :query => query, :results => results, :template => :doc_server, :type => :search ) self.body = Templates::Engine.render(options) end def search_for_object splitquery = query.split(/\s+/).map {|c| c.downcase }.reject {|m| m.empty? } self.results = run_verifier(Registry.all).select {|o| o.path.downcase.include?(query.downcase) }.reject {|o| name = (o.type == :method ? o.name(true) : o.name).to_s.downcase !name.include?(query.downcase) || case o.type when :method !(query =~ /[#.]/) && query.include?("::") when :class, :module, :constant, :class_variable query =~ /[#.]/ end }.sort_by {|o| name = (o.type == :method ? o.name(true) : o.name).to_s name.length.to_f / query.length.to_f } end end end end end yard-0.8.7.3/lib/yard/server/templates/0000755000004100000410000000000012261240652017667 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/default/0000755000004100000410000000000012261240652021313 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/default/method_details/0000755000004100000410000000000012261240652024300 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/default/method_details/html/0000755000004100000410000000000012261240652025244 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/default/method_details/html/permalink.erb0000644000004100000410000000027312261240652027722 0ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/default/method_details/html/setup.rb0000644000004100000410000000011712261240652026730 0ustar www-datawww-datadef init super sections.place(:permalink).after_any(:method_signature) end yard-0.8.7.3/lib/yard/server/templates/default/layout/0000755000004100000410000000000012261240652022630 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/default/layout/html/0000755000004100000410000000000012261240652023574 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/default/layout/html/script_setup.erb0000644000004100000410000000052212261240652027011 0ustar www-datawww-data yard-0.8.7.3/lib/yard/server/templates/default/layout/html/setup.rb0000644000004100000410000000014612261240652025262 0ustar www-datawww-datadef javascripts super + %w(js/autocomplete.js) end def stylesheets super + %w(css/custom.css) endyard-0.8.7.3/lib/yard/server/templates/default/layout/html/breadcrumb.erb0000644000004100000410000000422112261240652026373 0ustar www-datawww-data yard-0.8.7.3/lib/yard/server/templates/default/fulldoc/0000755000004100000410000000000012261240652022743 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/default/fulldoc/html/0000755000004100000410000000000012261240652023707 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/default/fulldoc/html/js/0000755000004100000410000000000012261240652024323 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/default/fulldoc/html/js/autocomplete.js0000644000004100000410000001750312261240652027370 0ustar www-datawww-data/* * jQuery Autocomplete plugin 1.1 * * Copyright (c) 2009 Jörn Zaefferer * * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html * * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $ */ eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}(';(3($){$.2e.1u({19:3(b,d){5 c=W b=="1B";d=$.1u({},$.M.1T,{Y:c?b:P,y:c?P:b,1J:c?$.M.1T.1J:10,X:d&&!d.1D?10:48},d);d.1y=d.1y||3(a){6 a};d.1v=d.1v||d.1R;6 A.I(3(){1M $.M(A,d)})},L:3(a){6 A.11("L",a)},1k:3(a){6 A.14("1k",[a])},2b:3(){6 A.14("2b")},28:3(a){6 A.14("28",[a])},24:3(){6 A.14("24")}});$.M=3(o,r){5 t={2Y:38,2S:40,2N:46,2I:9,2E:13,2B:27,2x:3I,2v:33,2p:34,2n:8};5 u=$(o).3r("19","3o").Q(r.2Q);5 p;5 m="";5 n=$.M.3c(r);5 s=0;5 k;5 h={1F:C};5 l=$.M.32(r,o,1Z,h);5 j;$.1Y.2X&&$(o.2U).11("45.19",3(){4(j){j=C;6 C}});u.11(($.1Y.2X?"43":"42")+".19",3(a){s=1;k=a.2M;3V(a.2M){O t.2Y:a.1d();4(l.N()){l.30()}w{12(0,D)}R;O t.2S:a.1d();4(l.N()){l.2D()}w{12(0,D)}R;O t.2v:a.1d();4(l.N()){l.2C()}w{12(0,D)}R;O t.2p:a.1d();4(l.N()){l.2A()}w{12(0,D)}R;O r.17&&$.1c(r.S)==","&&t.2x:O t.2I:O t.2E:4(1Z()){a.1d();j=D;6 C}R;O t.2B:l.Z();R;3J:1P(p);p=1O(12,r.1J);R}}).2t(3(){s++}).3E(3(){s=0;4(!h.1F){2r()}}).2q(3(){4(s++>1&&!l.N()){12(0,D)}}).11("1k",3(){5 c=(1r.7>1)?1r[1]:P;3 1N(q,a){5 b;4(a&&a.7){16(5 i=0;i1){5 f=r.S.7;5 c=$(o).18().1I;5 d,1H=0;$.I(b,3(i,a){1H+=a.7;4(c<=1H){d=i;6 C}1H+=f});b[d]=v;v=b.3f(r.S)}v+=r.S}u.K(v);1l();u.14("L",[e.y,e.F]);6 D}3 12(b,c){4(k==t.2N){l.Z();6}5 a=u.K();4(!c&&a==m)6;m=a;a=1m(a);4(a.7>=r.29){u.Q(r.26);4(!r.1s)a=a.J();21(a,3a,1l)}w{1q();l.Z()}};3 15(b){4(!b)6[""];4(!r.17)6[$.1c(b)];6 $.4h(b.23(r.S),3(a){6 $.1c(b).7?$.1c(a):P})}3 1m(a){4(!r.17)6 a;5 c=15(a);4(c.7==1)6 c[0];5 b=$(o).18().1I;4(b==a.7){c=15(a)}w{c=15(a.22(a.37(b),""))}6 c[c.7-1]}3 1G(q,a){4(r.1G&&(1m(u.K()).J()==q.J())&&k!=t.2n){u.K(u.K()+a.37(1m(m).7));$(o).18(m.7,m.7+a.7)}};3 2r(){1P(p);p=1O(1l,4g)};3 1l(){5 c=l.N();l.Z();1P(p);1q();4(r.36){u.1k(3(a){4(!a){4(r.17){5 b=15(u.K()).1n(0,-1);u.K(b.3f(r.S)+(b.7?r.S:""))}w{u.K("");u.14("L",P)}}})}};3 3a(q,a){4(a&&a.7&&s){1q();l.35(a,q);1G(q,a[0].F);l.20()}w{1l()}};3 21(f,d,g){4(!r.1s)f=f.J();5 e=n.31(f);4(e&&e.7){d(f,e)}w 4((W r.Y=="1B")&&(r.Y.7>0)){5 c={4f:+1M 4e()};$.I(r.2Z,3(a,b){c[a]=W b=="3"?b():b});$.4d({4c:"4b",4a:"19"+o.49,2V:r.2V,Y:r.Y,y:$.1u({q:1m(f),47:r.X},c),44:3(a){5 b=r.1A&&r.1A(a)||1A(a);n.1i(f,b);d(f,b)}})}w{l.2T();g(f)}};3 1A(c){5 d=[];5 b=c.23("\\n");16(5 i=0;i]*)("+a.22(/([\\^\\$\\(\\)\\[\\]\\{\\}\\*\\.\\+\\?\\|\\\\])/2K,"\\\\$1")+")(?![^<>]*>)(?![^&;]+;)","2K"),"<2J>$1")},1D:D,1E:3S};$.M.3c=3(g){5 h={};5 j=0;3 1f(s,a){4(!g.1s)s=s.J();5 i=s.2H(a);4(g.1w=="3R"){i=s.J().1k("\\\\b"+a.J())}4(i==-1)6 C;6 i==0||g.1w};3 1i(q,a){4(j>g.1g){1o()}4(!h[q]){j++}h[q]=a}3 1e(){4(!g.y)6 C;5 f={},2G=0;4(!g.Y)g.1g=1;f[""]=[];16(5 i=0,2F=g.y.7;i<2F;i++){5 c=g.y[i];c=(W c=="1B")?[c]:c;5 d=g.1v(c,i+1,g.y.7);4(d===C)1V;5 e=d.3Q(0).J();4(!f[e])f[e]=[];5 b={F:d,y:c,L:g.1z&&g.1z(c)||d};f[e].1U(b);4(2G++0){5 c=h[k];$.I(c,3(i,x){4(1f(x.F,q)){a.1U(x)}})}}6 a}w 4(h[q]){6 h[q]}w 4(g.1f){16(5 i=q.7-1;i>=g.29;i--){5 c=h[q.3O(0,i)];4(c){5 a=[];$.I(c,3(i,x){4(1f(x.F,q)){a[a.7]=x}});6 a}}}6 P}}};$.M.32=3(e,g,f,k){5 h={H:"3N"};5 j,z=-1,y,1t="",1S=D,G,B;3 2y(){4(!1S)6;G=$("<3M/>").Z().Q(e.2P).T("3L","3K").1Q(1K.2w);B=$("<3H/>").1Q(G).3G(3(a){4(U(a).2u&&U(a).2u.3F()==\'2s\'){z=$("1L",B).1h(h.H).3D(U(a));$(U(a)).Q(h.H)}}).2q(3(a){$(U(a)).Q(h.H);f();g.2t();6 C}).3C(3(){k.1F=D}).3B(3(){k.1F=C});4(e.E>0)G.T("E",e.E);1S=C}3 U(a){5 b=a.U;3A(b&&b.3z!="2s")b=b.3y;4(!b)6[];6 b}3 V(b){j.1n(z,z+1).1h(h.H);2o(b);5 a=j.1n(z,z+1).Q(h.H);4(e.1D){5 c=0;j.1n(0,z).I(3(){c+=A.1a});4((c+a[0].1a-B.1b())>B[0].3x){B.1b(c+a[0].1a-B.3w())}w 4(c=j.1j()){z=0}}3 2m(a){6 e.X&&e.X").3v(e.1y(a,1t)).Q(i%2==0?"3u":"3P").1Q(B)[0];$.y(c,"2k",y[i])}j=B.3t("1L");4(e.1X){j.1n(0,1).Q(h.H);z=0}4($.2e.2W)B.2W()}6{35:3(d,q){2y();y=d;1t=q;2l()},2D:3(){V(1)},30:3(){V(-1)},2C:3(){4(z!=0&&z-8<0){V(-z)}w{V(-8)}},2A:3(){4(z!=j.1j()-1&&z+8>j.1j()){V(j.1j()-1-z)}w{V(8)}},Z:3(){G&&G.Z();j&&j.1h(h.H);z=-1},N:3(){6 G&&G.3s(":N")},3q:3(){6 A.N()&&(j.2j("."+h.H)[0]||e.1X&&j[0])},20:3(){5 a=$(g).3p();G.T({E:W e.E=="1B"||e.E>0?e.E:$(g).E(),2i:a.2i+g.1a,1W:a.1W}).20();4(e.1D){B.1b(0);B.T({2L:e.1E,3n:\'3X\'});4($.1Y.3m&&W 1K.2w.3l.2L==="1x"){5 c=0;j.I(3(){c+=A.1a});5 b=c>e.1E;B.T(\'3k\',b?e.1E:c);4(!b){j.E(B.E()-2R(j.T("2O-1W"))-2R(j.T("2O-3j")))}}}},2g:3(){5 a=j&&j.2j("."+h.H).1h(h.H);6 a&&a.7&&$.y(a[0],"2k")},2T:3(){B&&B.2z()},1p:3(){G&&G.3i()}}};$.2e.18=3(b,f){4(b!==1x){6 A.I(3(){4(A.2d){5 a=A.2d();4(f===1x||b==f){a.4n("2c",b);a.3h()}w{a.4m(D);a.4l("2c",b);a.4k("2c",f);a.3h()}}w 4(A.3g){A.3g(b,f)}w 4(A.1C){A.1C=b;A.3e=f}})}5 c=A[0];4(c.2d){5 e=1K.18.4j(),3d=c.F,2a="<->",2f=e.3b.7;e.3b=2a;5 d=c.F.2H(2a);c.F=3d;A.18(d,d+2f);6{1I:d,39:d+2f}}w 4(c.1C!==1x){6{1I:c.1C,39:c.3e}}}})(4i);',62,272,'|||function|if|var|return|length|||||||||||||||||||||||||else||data|active|this|list|false|true|width|value|element|ACTIVE|each|toLowerCase|val|result|Autocompleter|visible|case|null|addClass|break|multipleSeparator|css|target|moveSelect|typeof|max|url|hide||bind|onChange||trigger|trimWords|for|multiple|selection|autocomplete|offsetHeight|scrollTop|trim|preventDefault|populate|matchSubset|cacheLength|removeClass|add|size|search|hideResultsNow|lastWord|slice|flush|unbind|stopLoading|arguments|matchCase|term|extend|formatMatch|matchContains|undefined|highlight|formatResult|parse|string|selectionStart|scroll|scrollHeight|mouseDownOnSelect|autoFill|progress|start|delay|document|li|new|findValueCallback|setTimeout|clearTimeout|appendTo|formatItem|needsInit|defaults|push|continue|left|selectFirst|browser|selectCurrent|show|request|replace|split|unautocomplete||loadingClass||setOptions|minChars|teststring|flushCache|character|createTextRange|fn|textLength|selected|in|top|filter|ac_data|fillList|limitNumberOfItems|BACKSPACE|movePosition|PAGEDOWN|click|hideResults|LI|focus|nodeName|PAGEUP|body|COMMA|init|empty|pageDown|ESC|pageUp|next|RETURN|ol|nullData|indexOf|TAB|strong|gi|maxHeight|keyCode|DEL|padding|resultsClass|inputClass|parseInt|DOWN|emptyList|form|dataType|bgiframe|opera|UP|extraParams|prev|load|Select|||display|mustMatch|substring||end|receiveData|text|Cache|orig|selectionEnd|join|setSelectionRange|select|remove|right|height|style|msie|overflow|off|offset|current|attr|is|find|ac_even|html|innerHeight|clientHeight|parentNode|tagName|while|mouseup|mousedown|index|blur|toUpperCase|mouseover|ul|188|default|absolute|position|div|ac_over|substr|ac_odd|charAt|word|180|RegExp|100|switch|400|auto|ac_loading|ac_results||ac_input|keydown|keypress|success|submit||limit|150|name|port|abort|mode|ajax|Date|timestamp|200|map|jQuery|createRange|moveEnd|moveStart|collapse|move'.split('|'),0,{}))yard-0.8.7.3/lib/yard/server/templates/default/fulldoc/html/images/0000755000004100000410000000000012261240652025154 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/default/fulldoc/html/images/processing.gif0000644000004100000410000000234312261240652030021 0ustar www-datawww-dataGIF89aҼܸت666&&&PPPpppVVVhhhFFFHHH222! NETSCAPE2.0! ,@pH dR Ĩth8 W e4Sib-kK'\n1|!!B C|Gvs A! !,W@p(| @ ˡÉD "Qzv$^QSPH$`d(qx CKx gy WWCA! , M "JdHb+Q\g!HTY#hp8r;>KeӉ`,I$H񌠈lÑxlv}1b6"h8`@(! !, YpCr\Kc nNǁBlFzR1 "`ǸBB !B !BvG ur GA! !,V@pHt . qhl(PRҹD˅%~]!GQf0p^9 PS} SS t} A;yard-0.8.7.3/lib/yard/server/templates/default/fulldoc/html/css/0000755000004100000410000000000012261240652024477 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/default/fulldoc/html/css/custom.css0000644000004100000410000000424312261240652026526 0ustar www-datawww-data#search_results h1 { margin-bottom: 0; } #search_results p { margin-top: 0; margin-bottom: 25px; } #search_results ul { list-style-position: inside; padding-left: 0; list-style: none; } #search_results ul li { padding: 7px 15px; font-size: 1.1em; } #search_frame { z-index: 9999; } form.search { position: relative; color: #fff; margin-top: 3px; padding: 7px; border: 1px solid #99f; width: 315px; background: #05a; -moz-border-radius: 4px; -webkit-border-radius: 4px; margin-bottom: 10px; } form.search input { margin-left: 5px; width: 250px; border: 1px solid #99f; -moz-border-radius: 3px; font-family: monospace; } #menu { padding-top: 5px; } #content h1 { margin-top: 0; border-top: 0; } #content.error { font-size: 1.2em; } #content.error p tt { font-size: 1.2em; } #content.error .note { padding: 12px; } .signature .permalink { float: right; font-size: 0.9em; } /* autocomplete */ .ac_results { padding: 0px; border: 1px solid black; width: 500px; overflow: hidden; z-index: 99999; } .ac_results ul { width: 100%; list-style-position: outside; list-style: none; padding: 0; margin: 0; } .ac_results li { cursor: pointer; margin: 0px; padding: 3px; display: block; font-family: sans-serif; font-size: 12px; line-height: 16px; overflow: hidden; } .ac_loading { background: white url('/images/processing.gif') right center no-repeat; } .ac_even { background: #fafafa; border: 1px dotted #fafafa; border-left-width: 0; border-right-width: 0; } .ac_odd { background: #f0f0f0; border: 1px dotted #f0f0f0; border-left-width: 0; border-right-width: 0; } .ac_over { background: #ddd; cursor: pointer; border: 1px dotted #fff; border-left-width: 0; border-right-width: 0; } #fade { display: none; position: absolute; top: 0px; left: 0; background: #eee; z-index: -1; width: 100%; height: 100%; border-top: 1px solid #e0e0e0; } #processing { position: absolute; width: 400px; height: 200px; margin: auto; background: #fff; padding: 10px 30px; z-index: 20; -webkit-box-shadow: 0px 0px 20px #444; -moz-box-shadow: 0px 0px 20px #444; -webkit-border-radius: 4px; display: none; } #processing img { display: block; position: absolute; bottom: 30px; left: 44%; } yard-0.8.7.3/lib/yard/server/templates/doc_server/0000755000004100000410000000000012261240652022022 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/doc_server/library_list/0000755000004100000410000000000012261240652024521 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/doc_server/library_list/html/0000755000004100000410000000000012261240652025465 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/doc_server/library_list/html/headers.erb0000644000004100000410000000204712261240652027575 0ustar www-datawww-data YARD Documentation Server <%= YARD::VERSION %> - Library Listing yard-0.8.7.3/lib/yard/server/templates/doc_server/library_list/html/title.erb0000644000004100000410000000022612261240652027300 0ustar www-datawww-data

            YARD Documentation Server <%= YARD::VERSION %>

            Library Listing (links without frames)

            yard-0.8.7.3/lib/yard/server/templates/doc_server/library_list/html/contents.erb0000644000004100000410000000115012261240652030011 0ustar www-datawww-data
              <% @libraries.sort_by {|name, y| name.downcase }.each do |name, library_versions| %>
            • <% library_versions = library_versions.dup %> <% first_lib = library_versions.pop %> <%= name %> <% if first_lib.version %> (<%= first_lib.version %><% if library_versions.size > 0 %>, <%= library_versions.reverse.map {|lib| "#{lib.version}" }.join(', ') %><% end %>) <% end %>
            • <% end %>
            yard-0.8.7.3/lib/yard/server/templates/doc_server/library_list/html/setup.rb0000644000004100000410000000007212261240652027151 0ustar www-datawww-datadef init sections :library_list, [:title, :contents] endyard-0.8.7.3/lib/yard/server/templates/doc_server/library_list/html/library_list.erb0000644000004100000410000000047712261240652030666 0ustar www-datawww-data <%= erb(:headers) %>
            <%= yieldall %>
            yard-0.8.7.3/lib/yard/server/templates/doc_server/search/0000755000004100000410000000000012261240652023267 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/doc_server/search/html/0000755000004100000410000000000012261240652024233 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/doc_server/search/html/search.erb0000644000004100000410000000130312261240652026167 0ustar www-datawww-data

            Search Results (for '<%= h @query %>')

            Showing <%= @visible_results.size %> of <%= @results.size %> results

              <% n = 1 %> <% @visible_results.each do |result| %> <% name = result.type == :method ? result.name(true).to_s : result.name.to_s %> <% path = name.gsub(/(#{Regexp.quote @query})/i, '\1') %>
            • <%= path %> <% if !result.namespace.root? %> (<%= result.namespace.path %>) <% end %>
            • <% n = n == 2 ? 1 : 2 %> <% end %>
            yard-0.8.7.3/lib/yard/server/templates/doc_server/search/html/setup.rb0000644000004100000410000000024712261240652025723 0ustar www-datawww-datadef init sections :search, [T('../default/layout')] end def search options.breadcrumb_title = h("Search for '#{@query}'") yieldall :contents => erb(:search) endyard-0.8.7.3/lib/yard/server/templates/doc_server/processing/0000755000004100000410000000000012261240652024176 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/doc_server/processing/html/0000755000004100000410000000000012261240652025142 5ustar www-datawww-datayard-0.8.7.3/lib/yard/server/templates/doc_server/processing/html/processing.erb0000644000004100000410000000444212261240652030014 0ustar www-datawww-data Processing <%= @library.to_s(false) %>

            Processing <%= @library.name %>

            <%= @library.name %> <% if @library.version %>(<%= @library.version %>)<% end %> is being processed. You'll be redirected when the pages are built, it shouldn't take much longer.

            yard-0.8.7.3/lib/yard/server/templates/doc_server/processing/html/setup.rb0000644000004100000410000000004312261240652026624 0ustar www-datawww-datadef init sections :processing endyard-0.8.7.3/lib/yard/server/webrick_adapter.rb0000644000004100000410000000240712261240652021347 0ustar www-datawww-datarequire 'webrick' module YARD module Server # The main adapter to initialize a WEBrick server. class WebrickAdapter < Adapter # Initializes a WEBrick server. If {Adapter#server_options} contains a # +:daemonize+ key set to true, the server will be daemonized. def start server_options[:ServerType] = WEBrick::Daemon if server_options[:daemonize] server = WEBrick::HTTPServer.new(server_options) server.mount('/', WebrickServlet, self) trap("INT") { server.shutdown } server.start end end # The main WEBrick servlet implementation, accepting only GET requests. class WebrickServlet < WEBrick::HTTPServlet::AbstractServlet attr_accessor :adapter def initialize(server, adapter) super self.adapter = adapter end def do_GET(request, response) status, headers, body = *adapter.router.call(request) response.status = status response.body = body.is_a?(Array) ? body[0] : body headers.each do |key, value| response[key] = value end end end end end # @private class WEBrick::HTTPRequest attr_accessor :version_supplied def xhr?; (self['X-Requested-With'] || "").downcase == 'xmlhttprequest' end end yard-0.8.7.3/lib/yard/server/library_version.rb0000644000004100000410000002376312261240652021442 0ustar www-datawww-datarequire 'fileutils' module YARD module Server # This exception is raised when {LibraryVersion#prepare!} fails, or discovers # that the library is not "prepared" to be served by class LibraryNotPreparedError < RuntimeError; end # A library version encapsulates a library's documentation at a specific version. # Although the version is optional, this allows for creating multiple documentation # points for a specific library, each representing a unique version. The term # "library" used in other parts of the YARD::Server documentation refers to # objects of this class unless otherwise noted. # # A library points to a location where a {#yardoc_file} is located so that # its documentation may be loaded and served. Optionally, a {#source_path} is # given to point to a location where any extra files (and {YARD::CLI::Yardoc .yardopts}) # should be loaded from. Both of these methods may not be known immediately, # since the yardoc file may not be built until later. Resolving the yardoc # file and source path are dependent on the specific library "source type" used. # Source types (known as "library source") are discussed in detail below. # # == Using with Adapters # A list of libraries need to be passed into adapters upon creation. In # most cases, you will never do this manually, but if you use a {RackMiddleware}, # you will need to pass in this list yourself. To build this list of libraries, # you should create a hash of library names mapped to an *Array* of LibraryVersion # objects. For example: # # {'mylib' => [LibraryVersion.new('mylib', '1.0', ...), # LibraryVersion.new('mylib', '2.0', ...)]} # # Note that you can also use {Adapter#add_library} for convenience. # # The "array" part is required, even for just one library version. # # == Library Sources # The {#source} method represents the library source type, ie. where the # library "comes from". It might come from "disk", or it might come from a # "gem" (technically the disk, but a separate type nonetheless). In these # two cases, the yardoc file sits somewhere on your filesystem, though # it may also be built dynamically if it does not yet exist. This behaviour # is controlled through the {#prepare!} method, which prepares the yardoc file # given a specific library source. We will see how this works in detail in # the following section. # # == Implementing a Custom Library Source # YARD can be extended to support custom library sources in order to # build or retrieve a yardoc file at runtime from many different locations. # # To implement this behaviour, two methods must be added to the +LibraryVersion+ # class, +#load_yardoc_from_SOURCE+ and +#source_path_for_SOURCE+. In both # cases, "SOURCE" represents the source type used in {#source} when creating # the library object. The +#source_path_for_SOURCE+ method is called upon # creation and should return the location where the source code for the library # lives. The load method is called from {#prepare!} if there is no yardoc file # and should set {#yardoc_file}. Below is a full example for # implementing a custom library source, +:http+, which reads packaged .yardoc # databases from zipped archives off of an HTTP server. # # @example Implementing a Custom Library Source # # Adds the source type "http" for .yardoc files zipped on HTTP servers # class LibraryVersion # def load_yardoc_from_http # return if yardoc_file # we have the library # # # otherwise download it in a thread and return immediately # Thread.new do # # zip/unzip method implementations are not shown # download_zip_file("http://mysite.com/yardocs/#{self}.zip") # unzip_file_to("/path/to/yardocs/#{self}") # self.yardoc_file = "/path/to/yardocs/#{self}/.yardoc" # self.source_path = self.yardoc_file # end # # # tell the server it's not ready yet (but it might be next time) # raise LibraryNotPreparedError # end # # # we set this later # def source_path_for_http; nil end # end # # # Creating a library of this source type: # LibraryVersion.new('name', '1.0', nil, :http) # class LibraryVersion # @return [String] the name of the library attr_accessor :name # @return [String] the version of the specific library attr_accessor :version # @return [String] the location of the yardoc file used to load the object # information from. # @return [nil] if no yardoc file exists yet. In this case, {#prepare!} will # be called on this library to build the yardoc file. attr_accessor :yardoc_file # @return [Symbol] the source type representing where the yardoc should be # loaded from. Defaults are +:disk+ and +:gem+, though custom sources # may be implemented. This value is used to inform {#prepare!} about how # to load the necessary data in order to display documentation for an object. # @see LibraryVersion LibraryVersion documentation for "Implementing a Custom Library Source" attr_accessor :source # @return [String] the location of the source code for a library. This # value is filled by calling +#source_path_for_SOURCE+ on this class. # @return [nil] if there is no source code # @see LibraryVersion LibraryVersion documentation for "Implementing a Custom Library Source" attr_accessor :source_path # @param [String] name the name of the library # @param [String] version the specific (usually, but not always, numeric) library # version # @param [String] yardoc the location of the yardoc file, or nil if it is # generated later # @param [Symbol] source the location of the files used to build the yardoc. # Builtin source types are +:disk+ or +:gem+. def initialize(name, version = nil, yardoc = nil, source = :disk) self.name = name self.yardoc_file = yardoc self.version = version self.source = source self.source_path = load_source_path end # @param [Boolean] url_format if true, returns the string in a URI-compatible # format (for appending to a URL). Otherwise, it is given in a more human # readable format. # @return [String] the string representation of the library. def to_s(url_format = true) version ? "#{name}#{url_format ? '/' : '-'}#{version}" : "#{name}" end # @return [Fixnum] used for Hash mapping. def hash; to_s.hash end # @return [Boolean] whether another LibraryVersion is equal to this one def eql?(other) other.is_a?(LibraryVersion) && other.name == name && other.version == version && other.yardoc_file == yardoc_file end alias == eql? alias equal? eql? # @note You should not directly override this method. Instead, implement # +load_yardoc_from_SOURCENAME+ when implementing loading for a specific # source type. See the {LibraryVersion} documentation for "Implementing # a Custom Library Source" # # Prepares a library to be displayed by the server. This callback is # performed before each request on a library to ensure that it is loaded # and ready to be viewed. If any steps need to be performed prior to loading, # they are performed through this method (though they should be implemented # through the +load_yardoc_from_SOURCE+ method). # # @raise [LibraryNotPreparedError] if the library is not ready to be # displayed. Usually when raising this error, you would simultaneously # begin preparing the library for subsequent requests, although this # is not necessary. def prepare! return if yardoc_file meth = "load_yardoc_from_#{source}" send(meth) if respond_to?(meth, true) end # @return [Gem::Specification] a gemspec object for a given library. Used # for :gem source types. # @return [nil] if there is no installed gem for the library def gemspec ver = version ? "= #{version}" : ">= 0" Gem.source_index.find_name(name, ver).first end protected # Called when a library of source type "disk" is to be prepared. In this # case, the {#yardoc_file} should already be set, so nothing needs to be # done. def load_yardoc_from_disk nil end # Called when a library of source type "gem" is to be prepared. In this # case, the {#yardoc_file} needs to point to the correct location for # the installed gem. The yardoc file is built if it has not been done. # # @raise [LibraryNotPreparedError] if the gem does not have an existing # yardoc file. def load_yardoc_from_gem require 'rubygems' ver = version ? "= #{version}" : ">= 0" self.yardoc_file = Registry.yardoc_file_for_gem(name, ver) unless yardoc_file && File.directory?(yardoc_file) Thread.new do # Build gem docs on demand log.debug "Building gem docs for #{to_s(false)}" CLI::Gems.run(name, ver) self.yardoc_file = Registry.yardoc_file_for_gem(name, ver) FileUtils.touch(File.join(yardoc_file, 'complete')) end end unless yardoc_file && File.exist?(File.join(yardoc_file, 'complete')) raise LibraryNotPreparedError end end # @return [String] the source path for a disk source def source_path_for_disk File.dirname(yardoc_file) if yardoc_file end # @return [String] the source path for a gem source def source_path_for_gem gemspec.full_gem_path if gemspec end private def load_source_path meth = "source_path_for_#{source}" send(meth) if respond_to?(meth, true) end end end endyard-0.8.7.3/lib/yard/server/rack_adapter.rb0000644000004100000410000000634012261240652020641 0ustar www-datawww-datarequire 'rack' require 'webrick/httputils' module YARD module Server # This class wraps the {RackAdapter} into a Rack-compatible middleware. # See {#initialize} for a list of options to pass via Rack's +#use+ method. # # @note You must pass a +:libraries+ option to the RackMiddleware via +#use+. To # read about how to return a list of libraries, see {LibraryVersion} or look # at the example below. # @example Using the RackMiddleware in a Rack application # libraries = {:mylib => [YARD::Server::LibraryVersion.new('mylib', nil, '/path/to/.yardoc')]} # use YARD::Server::RackMiddleware, :libraries => libraries # class RackMiddleware # Creates a new Rack-based middleware for serving YARD documentation. # # @param app the next Rack middleware in the stack # @option opts [Hash{String=>Array}] :libraries ({}) # the map of libraries to serve through the adapter. This option is *required*. # @option opts [Hash] :options ({}) a list of options to pass to the adapter. # See {Adapter#options} for a list. # @option opts [Hash] :server_options ({}) a list of options to pass to the server. # See {Adapter#server_options} for a list. def initialize(app, opts = {}) args = [opts[:libraries] || {}, opts[:options] || {}, opts[:server_options] || {}] @app = app @adapter = RackAdapter.new(*args) end def call(env) status, headers, body = *@adapter.call(env) if status == 404 @app.call(env) else [status, headers, body] end end end # A server adapter to respond to requests using the Rack server infrastructure. class RackAdapter < Adapter include WEBrick::HTTPUtils # Responds to Rack requests and builds a response with the {Router}. # @return [Array(Numeric,Hash,Array)] the Rack-style response def call(env) request = Rack::Request.new(env) request.path_info = unescape(request.path_info) # unescape things like %3F router.call(request) rescue StandardError => ex log.backtrace(ex) [500, {'Content-Type' => 'text/plain'}, [ex.message + "\n" + ex.backtrace.join("\n")]] end # Starts the +Rack::Server+. This method will pass control to the server and # block. # @return [void] def start server = Rack::Server.new(server_options) server.instance_variable_set("@app", self) print_start_message(server) server.start end private def print_start_message(server) opts = server.default_options.merge(server.options) log.puts ">> YARD #{YARD::VERSION} documentation server at http://#{opts[:Host]}:#{opts[:Port]}" # Only happens for Mongrel return unless server.server.to_s == "Rack::Handler::Mongrel" log.puts ">> #{server.server.class_name} web server (running on Rack)" log.puts ">> Listening on #{opts[:Host]}:#{opts[:Port]}, CTRL+C to stop" end end end end # @private class Rack::Request attr_accessor :version_supplied alias query params def xhr?; (env['HTTP_X_REQUESTED_WITH'] || "").downcase == "xmlhttprequest" end end yard-0.8.7.3/lib/yard/server/adapter.rb0000644000004100000410000001027712261240652017645 0ustar www-datawww-datamodule YARD module Server # Short circuits a request by raising an error. This exception is caught # by {Commands::Base#call} to immediately end a request and return a response. class FinishRequest < RuntimeError; end # Raises an error if a resource is not found. This exception is caught by # {Commands::Base#call} to immediately end a request and return a 404 response # code. If a message is provided, the body is set to the exception message. class NotFoundError < RuntimeError; end # This class implements the bridge between the {Router} and the server # backend for a specific server type. YARD implements concrete adapters # for WEBrick and Rack respectively, though other adapters can be made # for other server architectures. # # == Subclassing Notes # To create a concrete adapter class, implement the {#start} method to # initiate the server backend. # # @abstract class Adapter # @return [String] the location where static files are located, if any. # To set this field on initialization, pass +:DocumentRoot+ to the # +server_opts+ argument in {#initialize} attr_accessor :document_root # @return [Hash{String=>Array}] a map of libraries. # @see LibraryVersion LibraryVersion for information on building a list of libraries # @see #add_library attr_accessor :libraries # @return [Hash] options passed and processed by adapters. The actual # options mostly depend on the adapters themselves. attr_accessor :options # @return [Hash] a set of options to pass to the server backend. Note # that +:DocumentRoot+ also sets the {#document_root}. attr_accessor :server_options # @return [Router] the router object used to route URLs to commands attr_accessor :router # Performs any global initialization for the adapter. # @note If you subclass this method, make sure to call +super+. # @return [void] def self.setup Templates::Template.extra_includes |= [YARD::Server::DocServerHelper] Templates::Engine.template_paths |= [File.dirname(__FILE__) + '/templates'] end # Performs any global shutdown procedures for the adapter. # @note If you subclass this method, make sure to call +super+. # @return [void] def self.shutdown Templates::Template.extra_includes -= [YARD::Server::DocServerHelper] Templates::Engine.template_paths -= [File.dirname(__FILE__) + '/templates'] end # Creates a new adapter object # # @param [Hash{String=>Array}] libs a list of libraries, # see {#libraries} for formulating this list. # @param [Hash] opts extra options to pass to the adapter # @option opts [Class] :router (Router) the router class to initialize as the # adapter's router. # @option opts [Boolean] :caching (false) whether or not caching is enabled # @option opts [Boolean] :single_library (false) whether to server documentation # for a single or multiple libraries (changes URL structure) def initialize(libs, opts = {}, server_opts = {}) self.class.setup self.libraries = libs self.options = opts self.server_options = server_opts self.document_root = server_options[:DocumentRoot] self.router = (options[:router] || Router).new(self) options[:adapter] = self log.debug "Serving libraries using #{self.class}: #{libraries.keys.join(', ')}" log.debug "Caching on" if options[:caching] log.debug "Document root: #{document_root}" if document_root end # Adds a library to the {#libraries} mapping for a given library object. # @example Adding a new library to an adapter # adapter.add_library LibraryVersion.new('mylib', '1.0', '/path/to/.yardoc') # @param [LibraryVersion] library a library to add def add_library(library) libraries[library.name] ||= [] libraries[library.name] |= [library] end # Implement this method to connect your adapter to your server. # @abstract def start raise NotImplementedError end end end end yard-0.8.7.3/lib/yard/parser/0000755000004100000410000000000012261240652015657 5ustar www-datawww-datayard-0.8.7.3/lib/yard/parser/c/0000755000004100000410000000000012261240652016101 5ustar www-datawww-datayard-0.8.7.3/lib/yard/parser/c/c_parser.rb0000644000004100000410000001500212261240652020222 0ustar www-datawww-datamodule YARD module Parser module C class CParser < Base def initialize(source, file = '(stdin)') @file = file @namespaces = {} @content = source @index = 0 @line = 1 @state = nil @newline = true @statements = [] @last_comment = nil @last_statement = nil end def parse parse_toplevel enumerator end def enumerator @statements end def tokenize raise NotImplementedError, "no tokenization support for C/C++ files" end private def parse_toplevel advance_loop do case char when /['"]/; consume_quote(char) when '#'; consume_directive when '/'; consume_comment when /\s/; consume_whitespace else consume_toplevel_statement end end end def consume_quote(type = '"') advance advance_loop do case char when "\n"; advance; nextline when '\\'; advance(2) when type; advance; return else advance end end end def consume_directive return(advance) unless @newline @last_comment = nil @last_statement = nil advance_loop do if char == '\\' && nextchar =~ /[\r\n]/ advance_loop { advance; break(nextline) if char == "\n" } elsif char == "\n" return end advance end end def consume_toplevel_statement @newline = false start = @index line = @line decl = consume_until(/[{;]/) return nil if decl =~ /\A\s*\Z/ statement = ToplevelStatement.new(nil, @file, line) @statements << statement attach_comment(statement) stmts = nil if prevchar == '{' stmts = consume_body_statements if decl =~ /\A(typedef|enum|class|#{struct}|union)/ consume_until(';') end end statement.source = @content[start..@index] statement.block = stmts statement.declaration = decl end def consume_body_statements stmts = [] brace_level = 1 while true strip_non_statement_data start, line = @index, @line consume_until(/[{};]/) brace_level += 1 if prevchar == '{' brace_level -= 1 if prevchar == '}' break if prevchar.empty? || (brace_level <= 0 && prevchar == '}') end_chr = @index end_chr -= 1 if prevchar == '}' src = @content[start...@index] if src && src !~ /\A\s*\Z|\A\}\Z/ stmt = BodyStatement.new(src, @file, line) attach_comment(stmt) stmts << stmt end end stmts end def strip_non_statement_data start = @index begin start = @index case char when /\s/; consume_whitespace when '#'; consume_directive when '/'; consume_comment end end until start == @index end def consume_whitespace advance_loop { nextline if char == "\n"; break if char =~ /\S/; advance } end def consume_comment(add_comment = true) return(advance) unless nextchar == '*' || nextchar == '/' line = @line type = nextchar == '*' ? :multi : :line advance(2) comment = "" advance_loop do comment << char if type == :multi nextline if char == "\n" if char(2) == '*/' if add_comment comment << '/' stmt = Comment.new(comment, @file, line) stmt.type = type attach_comment(stmt) @statements << stmt end return advance(2) end elsif char == "\n" if add_comment stmt = Comment.new(comment[0...-1], @file, line) stmt.type = type attach_comment(stmt) @statements << stmt end return end advance end end def consume_until(end_char, bracket_level = 0, brace_level = 0, add_comment = true) end_char = /#{end_char}/ if end_char.is_a?(String) start = @index advance_loop do chr = char case chr when /\s/; consume_whitespace when /['"]/; consume_quote(char) when '#'; consume_directive when '/'; consume_comment(add_comment) when '{'; advance; brace_level += 1 when '}'; advance; brace_level -= 1 when '('; advance; bracket_level += 1 when ')'; advance; bracket_level -= 1 else advance end @newline = false if chr !~ /\s/ if chr =~ end_char && (chr == '{' || chr == '(') break elsif chr =~ end_char && bracket_level <= 0 && brace_level <= 0 break end end return @content[start...@index] end def attach_comment(statement) if Comment === statement if @last_statement && @last_statement.line == statement.line @last_statement.comments = statement statement.statement = @last_statement end @last_comment = statement @last_statement = nil else if @last_comment statement.comments = @last_comment @last_comment.statement = statement end @last_statement = statement @last_comment = nil end end def advance(num = 1) @index += num end def back(num = 1) @index -= num end def advance_loop(&block) while @index <= @content.size; yield end end def nextline @line += 1 @newline = true end def char(num = 1) @content[@index, num] end def prevchar(num = 1) @content[@index - 1, num] end def nextchar(num = 1) @content[@index + 1, num] end def struct /struct\s[:alnum:]+\s\{/ end end end end end yard-0.8.7.3/lib/yard/parser/c/statement.rb0000644000004100000410000000245512261240652020440 0ustar www-datawww-datamodule YARD module Parser module C class Statement attr_accessor :source attr_accessor :line attr_accessor :file # @deprecated Groups are now defined by directives # @see Tags::GroupDirective attr_accessor :group attr_accessor :comments_hash_flag def initialize(source, file = nil, line = nil) @source = source @file = file @line = line end def line_range line...(line + source.count("\n")) end def comments_range comments.line_range end def first_line source.split(/\n/).first end def show "\t#{line}: #{first_line}" end end class BodyStatement < Statement attr_accessor :comments end class ToplevelStatement < Statement attr_accessor :block attr_accessor :declaration attr_accessor :comments end class Comment < Statement include CommentParser attr_accessor :type attr_accessor :overrides attr_accessor :statement def initialize(source, file = nil, line = nil) super(parse_comments(source), file, line) end def comments; self end end end end end yard-0.8.7.3/lib/yard/parser/c/comment_parser.rb0000644000004100000410000001105012261240652021441 0ustar www-datawww-datamodule YARD module Parser module C module CommentParser protected def parse_comments(comments) @overrides = [] spaces = nil comments = remove_private_comments(comments) comments = comments.split(/\r?\n/).map do |line| line.gsub!(%r{^\s*/?\*/?}, '') line.gsub!(%r{\*/\s*$}, '') if line =~ /^\s*$/ next if spaces.nil? next "" end spaces = (line[/^(\s+)/, 1] || "").size if spaces.nil? line.gsub(/^\s{0,#{spaces}}/, '').rstrip end.compact comments = parse_overrides(comments) comments = parse_callseq(comments) comments.join("\n") end private def parse_overrides(comments) comments.map do |line| type, name = *line.scan(/^\s*Document-(class|module|method|const):\s*(\S.*)\s*$/).first if type @overrides << [type.to_sym, name] nil else line end end.compact end def parse_callseq(comments) return comments unless comments[0] =~ /\Acall-seq:\s*(\S.+)?/ if $1 comments[0] = " #{$1}" else comments.shift end overloads = [] seen_data = false while comments.first =~ /^\s+(\S.+)/ || comments.first =~ /^\s*$/ line = comments.shift.strip break if line.empty? && seen_data next if line.empty? seen_data = true line.sub!(/^\w+[\.#]/, '') signature, types = *line.split(/ [-=]> /) types = parse_types(types) if signature.sub!(/\[?\s*(\{(?:\s*\|(.+?)\|)?.*\})\s*\]?\s*$/, '') && $1 blk, blkparams = $1, $2 else blk, blkparams = nil, nil end case signature when /^(\w+)\s*=\s+(\w+)/ signature = "#{$1}=(#{$2})" when /^\w+\s+\S/ signature = signature.split(/\s+/) signature = "#{signature[1]}#{signature[2] ? '(' + signature[2..-1].join(' ') + ')' : ''}" when /^\w+\[(.+?)\]\s*(=)?/ signature = "[]#{$2}(#{$1})" when /^\w+\s+(#{CodeObjects::METHODMATCH})\s+(\w+)/ signature = "#{$1}(#{$2})" end break unless signature =~ /^#{CodeObjects::METHODNAMEMATCH}/ signature = signature.rstrip overloads << "@overload #{signature}" overloads << " @yield [#{blkparams}]" if blk overloads << " @return [#{types.join(', ')}]" unless types.empty? end comments + [""] + overloads end def parse_types(types) if types =~ /true or false/ ["Boolean"] else (types||"").split(/,| or /).map do |t| case t.strip.gsub(/^an?_/, '') when "class"; "Class" when "obj", "object", "anObject"; "Object" when "arr", "array", "anArray", /^\[/; "Array" when /^char\s*\*/, "char", "str", "string", "new_str"; "String" when "enum", "anEnumerator"; "Enumerator" when "exc", "exception"; "Exception" when "proc", "proc_obj", "prc"; "Proc" when "binding"; "Binding" when "hsh", "hash", "aHash"; "Hash" when "ios", "io"; "IO" when "file"; "File" when "float"; "Float" when "time", "new_time"; "Time" when "dir", "aDir"; "Dir" when "regexp", "new_regexp"; "Regexp" when "matchdata"; "MatchData" when "encoding"; "Encoding" when "fixnum", "fix"; "Fixnum" when /^(?:un)?signed$/, /^(?:(?:un)?signed\s*)?(?:short|int|long|long\s+long)$/, "integer", "Integer"; "Integer" when "num", "numeric", "Numeric", "number"; "Numeric" when "aBignum"; "Bignum" when "nil"; "nil" when "true"; "true" when "false"; "false" when "bool", "boolean", "Boolean"; "Boolean" when "self"; "self" when /^[-+]?\d/; t when /[A-Z][_a-z0-9]+/; t end end.compact end end def remove_private_comments(comment) comment = comment.gsub(/\/?\*--\n(.*?)\/?\*\+\+/m, '') comment = comment.sub(/\/?\*--\n.*/m, '') comment end end end end end yard-0.8.7.3/lib/yard/parser/source_parser.rb0000644000004100000410000004632712261240652021074 0ustar www-datawww-datarequire 'stringio' require 'ostruct' module YARD module Parser # Raised when an object is recognized but cannot be documented. This # generally occurs when the Ruby syntax used to declare an object is # too dynamic in nature. class UndocumentableError < Exception; end # Raised when the parser sees a Ruby syntax error class ParserSyntaxError < UndocumentableError; end # Responsible for parsing a list of files in order. The # {#parse} method of this class can be called from the # {SourceParser#globals} globals state list to re-enter # parsing for the remainder of files in the list recursively. # # @see Processor#parse_remaining_files class OrderedParser # @return [Array] the list of remaining files to parse attr_accessor :files # Creates a new OrderedParser with the global state and a list # of files to parse. # # @note OrderedParser sets itself as the +ordered_parser+ key on # global_state for later use in {Handlers::Processor}. # @param [OpenStruct] global_state a structure containing all global # state during parsing # @param [Array] files the list of files to parse def initialize(global_state, files) @global_state = global_state @files = files.dup @global_state.ordered_parser = self end # Parses the remainder of the {#files} list. # # @see Processor#parse_remaining_files def parse while file = files.shift log.capture("Parsing #{file}") do SourceParser.new(SourceParser.parser_type, @global_state).parse(file) end end end end # Responsible for parsing a source file into the namespace. Parsing # also invokes handlers to process the parsed statements and generate # any code objects that may be recognized. # # == Custom Parsers # SourceParser allows custom parsers to be registered and called when # a certain filetype is recognized. To register a parser and hook it # up to a set of file extensions, call {register_parser_type} # # @see register_parser_type # @see Handlers::Base # @see CodeObjects::Base class SourceParser SHEBANG_LINE = /\A\s*#!\S+/ ENCODING_LINE = /\A(?:\s*#*!.*\r?\n)?\s*(?:#+|\/\*+|\/\/+).*coding\s*[:=]{1,2}\s*([a-z\d_\-]+)/i # Byte order marks for various encodings # @since 0.7.0 ENCODING_BYTE_ORDER_MARKS = { 'utf-8' => "\xEF\xBB\xBF", # Not yet supported #'utf-16be' => "\xFE\xFF", #'utf-16le' => "\xFF\xFE", #'utf-32be' => "\x00\x00\xFF\xFE", #'utf-32le' => "\xFF\xFE", } class << self # @return [Symbol] the default parser type (defaults to :ruby) attr_reader :parser_type def parser_type=(value) @parser_type = validated_parser_type(value) end # Parses a path or set of paths # # @param [String, Array] paths a path, glob, or list of paths to # parse # @param [Array] excluded a list of excluded path matchers # @param [Fixnum] level the logger level to use during parsing. See # {YARD::Logger} # @return [void] def parse(paths = ["{lib,app}/**/*.rb", "ext/**/*.c"], excluded = [], level = log.level) log.debug("Parsing #{paths.inspect} with `#{parser_type}` parser") excluded = excluded.map do |path| case path when Regexp; path else Regexp.new(path.to_s, Regexp::IGNORECASE) end end files = [paths].flatten. map {|p| File.directory?(p) ? "#{p}/**/*.{rb,c}" : p }. map {|p| p.include?("*") ? Dir[p].sort_by {|f| f.length } : p }.flatten. reject {|p| !File.file?(p) || excluded.any? {|re| p =~ re } } log.enter_level(level) do parse_in_order(*files.uniq) end end # Parses a string +content+ # # @param [String] content the block of code to parse # @param [Symbol] ptype the parser type to use. See {parser_type}. # @return the parser object that was used to parse +content+ def parse_string(content, ptype = parser_type) new(ptype).parse(StringIO.new(content)) end # Tokenizes but does not parse the block of code # # @param [String] content the block of code to tokenize # @param [Symbol] ptype the parser type to use. See {parser_type}. # @return [Array] a list of tokens def tokenize(content, ptype = parser_type) new(ptype).tokenize(content) end # Registers a new parser type. # # @example Registering a parser for "java" files # SourceParser.register_parser_type :java, JavaParser, 'java' # @param [Symbol] type a symbolic name for the parser type # @param [Base] parser_klass a class that implements parsing and tokenization # @param [Array, String, Regexp] extensions a list of extensions or a # regex to match against the file extension # @return [void] # @see Parser::Base def register_parser_type(type, parser_klass, extensions = nil) unless Base > parser_klass raise ArgumentError, "expecting parser_klass to be a subclass of YARD::Parser::Base" end parser_type_extensions[type.to_sym] = extensions if extensions parser_types[type.to_sym] = parser_klass end # @return [Hash{Symbol=>Object}] a list of registered parser types # @private # @since 0.5.6 attr_reader :parser_types undef parser_types def parser_types; @@parser_types ||= {} end def parser_types=(value) @@parser_types = value end # @return [Hash] a list of registered parser type extensions # @private # @since 0.5.6 attr_reader :parser_type_extensions undef parser_type_extensions def parser_type_extensions; @@parser_type_extensions ||= {} end def parser_type_extensions=(value) @@parser_type_extensions = value end # Finds a parser type that is registered for the extension. If no # type is found, the default Ruby type is returned. # # @return [Symbol] the parser type to be used for the extension # @since 0.5.6 def parser_type_for_extension(extension) type = parser_type_extensions.find do |t, exts| [exts].flatten.any? {|ext| ext === extension } end validated_parser_type(type ? type.first : :ruby) end # Returns the validated parser type. Basically, enforces that :ruby # type is never set if the Ripper library is not available # # @param [Symbol] type the parser type to set # @return [Symbol] the validated parser type # @private def validated_parser_type(type) !defined?(::Ripper) && type == :ruby ? :ruby18 : type end # @group Parser Callbacks # Registers a callback to be called before a list of files is parsed # via {parse}. The block passed to this method will be called on # subsequent parse calls. # # @example Installing a simple callback # SourceParser.before_parse_list do |files, globals| # puts "Starting to parse..." # end # YARD.parse('lib/**/*.rb') # # prints "Starting to parse..." # # @example Setting global state # SourceParser.before_parse_list do |files, globals| # globals.method_count = 0 # end # SourceParser.after_parse_list do |files, globals| # puts "Found #{globals.method_count} methods" # end # class MyCountHandler < Handlers::Ruby::Base # handles :def, :defs # process { globals.method_count += 1 } # end # YARD.parse # # Prints: "Found 37 methods" # # @example Using a global callback to cancel parsing # SourceParser.before_parse_list do |files, globals| # return false if files.include?('foo.rb') # end # # YARD.parse(['foo.rb', 'bar.rb']) # callback cancels this method # YARD.parse('bar.rb') # parses normally # # @yield [files, globals] the yielded block is called once before # parsing all files # @yieldparam [Array] files the list of files that will be parsed. # @yieldparam [OpenStruct] globals a global structure to store arbitrary # state for post processing (see {Handlers::Processor#globals}) # @yieldreturn [Boolean] if the block returns +false+, parsing is # cancelled. # @return [Proc] the yielded block # @see after_parse_list # @see before_parse_file # @since 0.7.0 def before_parse_list(&block) before_parse_list_callbacks << block end # Registers a callback to be called after a list of files is parsed # via {parse}. The block passed to this method will be called on # subsequent parse calls. # # @example Printing results after parsing occurs # SourceParser.after_parse_list do # puts "Finished parsing!" # end # YARD.parse # # Prints "Finished parsing!" after parsing files # @yield [files, globals] the yielded block is called once before # parsing all files # @yieldparam [Array] files the list of files that will be parsed. # @yieldparam [OpenStruct] globals a global structure to store arbitrary # state for post processing (see {Handlers::Processor#globals}) # @yieldreturn [void] the return value for the block is ignored. # @return [Proc] the yielded block # @see before_parse_list # @see before_parse_file # @since 0.7.0 def after_parse_list(&block) after_parse_list_callbacks << block end # Registers a callback to be called before an individual file is parsed. # The block passed to this method will be called on subsequent parse # calls. # # To register a callback that is called before the entire list of files # is processed, see {before_parse_list}. # # @example Installing a simple callback # SourceParser.before_parse_file do |parser| # puts "I'm parsing #{parser.file}" # end # YARD.parse('lib/**/*.rb') # # prints: # "I'm parsing lib/foo.rb" # "I'm parsing lib/foo_bar.rb" # "I'm parsing lib/last_file.rb" # # @example Cancel parsing of any test_*.rb files # SourceParser.before_parse_file do |parser| # return false if parser.file =~ /^test_.+\.rb$/ # end # # @yield [parser] the yielded block is called once before each # file that is parsed. This might happen many times for a single # codebase. # @yieldparam [SourceParser] parser the parser object that will {#parse} # the file. # @yieldreturn [Boolean] if the block returns +false+, parsing for # the file is cancelled. # @return [Proc] the yielded block # @see after_parse_file # @see before_parse_list # @since 0.7.0 def before_parse_file(&block) before_parse_file_callbacks << block end # Registers a callback to be called after an individual file is parsed. # The block passed to this method will be called on subsequent parse # calls. # # To register a callback that is called after the entire list of files # is processed, see {after_parse_list}. # # @example Printing the length of each file after it is parsed # SourceParser.after_parse_file do |parser| # puts "#{parser.file} is #{parser.contents.size} characters" # end # YARD.parse('lib/**/*.rb') # # prints: # "lib/foo.rb is 1240 characters" # "lib/foo_bar.rb is 248 characters" # # @yield [parser] the yielded block is called once after each file # that is parsed. This might happen many times for a single codebase. # @yieldparam [SourceParser] parser the parser object that parsed # the file. # @yieldreturn [void] the return value for the block is ignored. # @return [Proc] the yielded block # @see before_parse_file # @see after_parse_list # @since 0.7.0 def after_parse_file(&block) after_parse_file_callbacks << block end # @return [Array] the list of callbacks to be called before # parsing a list of files. Should only be used for testing. # @since 0.7.0 def before_parse_list_callbacks @before_parse_list_callbacks ||= [] end # @return [Array] the list of callbacks to be called after # parsing a list of files. Should only be used for testing. # @since 0.7.0 def after_parse_list_callbacks @after_parse_list_callbacks ||= [] end # @return [Array] the list of callbacks to be called before # parsing a file. Should only be used for testing. # @since 0.7.0 def before_parse_file_callbacks @before_parse_file_callbacks ||= [] end # @return [Array] the list of callbacks to be called after # parsing a file. Should only be used for testing. # @since 0.7.0 def after_parse_file_callbacks @after_parse_file_callbacks ||= [] end # @endgroup private # Parses a list of files in a queue. # # @param [Array] files a list of files to queue for parsing # @return [void] def parse_in_order(*files) global_state = OpenStruct.new before_parse_list_callbacks.each do |cb| return if cb.call(files, global_state) == false end OrderedParser.new(global_state, files).parse after_parse_list_callbacks.each do |cb| cb.call(files, global_state) end end end register_parser_type :ruby, Ruby::RubyParser register_parser_type :ruby18, Ruby::Legacy::RubyParser register_parser_type :c, C::CParser, ['c', 'cc', 'cxx', 'cpp'] self.parser_type = :ruby # @return [String] the filename being parsed by the parser. attr_accessor :file # @return [Symbol] the parser type associated with the parser instance. # This should be set by the {#initialize constructor}. attr_reader :parser_type # @return [OpenStruct] an open struct containing arbitrary global state # shared between files and handlers. # @since 0.7.0 attr_reader :globals # @return [String] the contents of the file to be parsed # @since 0.7.0 attr_reader :contents # @overload initialize(parser_type = SourceParser.parser_type, globals = nil) # Creates a new parser object for code parsing with a specific parser type. # # @param [Symbol] parser_type the parser type to use # @param [OpenStruct] globals global state to be re-used across separate source files def initialize(parser_type = SourceParser.parser_type, globals1 = nil, globals2 = nil) globals = [true, false].include?(globals1) ? globals2 : globals1 @file = '(stdin)' @globals = globals || OpenStruct.new self.parser_type = parser_type end # The main parser method. This should not be called directly. Instead, # use the class methods {parse} and {parse_string}. # # @param [String, #read, Object] content the source file to parse # @return [Object, nil] the parser object used to parse the source def parse(content = __FILE__) case content when String @file = File.cleanpath(content) content = convert_encoding(File.read_binary(file)) checksum = Registry.checksum_for(content) return if Registry.checksums[file] == checksum if Registry.checksums.has_key?(file) log.info "File '#{file}' was modified, re-processing..." end Registry.checksums[@file] = checksum self.parser_type = parser_type_for_filename(file) else content = content.read if content.respond_to? :read end @contents = content @parser = parser_class.new(content, file) self.class.before_parse_file_callbacks.each do |cb| return @parser if cb.call(self) == false end @parser.parse post_process self.class.after_parse_file_callbacks.each do |cb| cb.call(self) end @parser rescue ArgumentError, NotImplementedError => e log.warn("Cannot parse `#{file}': #{e.message}") log.backtrace(e, :warn) rescue ParserSyntaxError => e log.warn(e.message.capitalize) log.backtrace(e, :warn) end # Tokenizes but does not parse the block of code using the current {#parser_type} # # @param [String] content the block of code to tokenize # @return [Array] a list of tokens def tokenize(content) @parser = parser_class.new(content, file) @parser.tokenize end private # Searches for encoding line and forces encoding # @since 0.5.3 def convert_encoding(content) return content unless content.respond_to?(:force_encoding) if content =~ ENCODING_LINE content.force_encoding($1) else content.force_encoding('binary') ENCODING_BYTE_ORDER_MARKS.each do |encoding, bom| bom.force_encoding('binary') if content[0,bom.size] == bom content.force_encoding(encoding) return content end end content.force_encoding('utf-8') # UTF-8 is default encoding content end end # Runs a {Handlers::Processor} object to post process the parsed statements. # @return [void] def post_process return unless @parser.respond_to? :enumerator return unless enumerator = @parser.enumerator post = Handlers::Processor.new(self) post.process(enumerator) end def parser_type=(value) @parser_type = self.class.validated_parser_type(value) end # Guesses the parser type to use depending on the file extension. # # @param [String] filename the filename to use to guess the parser type # @return [Symbol] a parser type that matches the filename def parser_type_for_filename(filename) ext = (File.extname(filename)[1..-1] || "").downcase type = self.class.parser_type_for_extension(ext) parser_type == :ruby18 && type == :ruby ? :ruby18 : type end # @since 0.5.6 def parser_class klass = self.class.parser_types[parser_type] raise ArgumentError, "invalid parser type '#{parser_type}' or unrecognized file", caller[1..-1] if !klass klass end end end end yard-0.8.7.3/lib/yard/parser/base.rb0000644000004100000410000000357012261240652017123 0ustar www-datawww-datamodule YARD module Parser # Represents the abstract base parser class that parses source code in # a specific way. A parser should implement {#parse}, {#tokenize} and # {#enumerator}. # # == Registering a Custom Parser # To register a parser, see {SourceParser.register_parser_type} # # @abstract # @see #parse # @see #tokenize # @see #enumerator # @since 0.5.6 class Base # Convenience method to create a new parser and {#parse} def self.parse(source, filename = nil) new(source, filename).parse end # This default constructor does nothing. The subclass is responsible for # storing the source contents and filename if they are required. # @param [String] source the source contents # @param [String] filename the name of the file if from disk def initialize(source, filename) raise NotImplementedError, "invalid parser implementation" end # This method should be implemented to parse the source and return itself. # @abstract # @return [Base] this method should return itself def parse raise NotImplementedError, "#{self.class} must implement #parse" end # This method should be implemented to tokenize given source # @abstract # @return [Array] a list/tree of lexical tokens def tokenize raise NotImplementedError, "#{self.class} does not support tokenization" end # This method should be implemented to return a list of semantic tokens # representing the source code to be post-processed. Otherwise the method # should return nil. # # @abstract # @return [Array] a list of semantic tokens representing the source code # to be post-processed # @return [nil] if no post-processing should be done def enumerator nil end end end endyard-0.8.7.3/lib/yard/parser/ruby/0000755000004100000410000000000012261240652016640 5ustar www-datawww-datayard-0.8.7.3/lib/yard/parser/ruby/ruby_parser.rb0000644000004100000410000005053112261240652021526 0ustar www-datawww-databegin require 'ripper'; rescue LoadError; end module YARD module Parser module Ruby # Ruby 1.9 parser # @!attribute [r] encoding_line # @!attribute [r] shebang_line # @!attribute [r] enumerator class RubyParser < Parser::Base def initialize(source, filename) @parser = RipperParser.new(source, filename) end def parse; @parser.parse end def tokenize; @parser.tokens end def enumerator; @parser.enumerator end def shebang_line; @parser.shebang_line end def encoding_line; @parser.encoding_line end end # Internal parser class # @since 0.5.6 class RipperParser < Ripper attr_reader :ast, :charno, :comments, :file, :tokens attr_reader :shebang_line, :encoding_line alias root ast def initialize(source, filename, *args) super @last_ns_token = nil @file = filename @source = source @tokens = [] @comments = {} @comments_range = {} @comments_flags = {} @heredoc_tokens = nil @heredoc_state = nil @map = {} @ns_charno = 0 @list = [] @charno = 0 @shebang_line = nil @encoding_line = nil @file_encoding = nil end def parse @ast = super @ast.full_source = @source @ast.file = @file freeze_tree insert_comments self end def enumerator ast.children end def file_encoding return nil unless defined?(::Encoding) return @file_encoding if @file_encoding return Encoding.default_internal unless @encoding_line if match = @encoding_line.match(SourceParser::ENCODING_LINE) @file_encoding = match.captures.last end end private MAPPINGS = { :BEGIN => "BEGIN", :END => "END", :alias => "alias", :array => :lbracket, :arg_paren => :lparen, :begin => "begin", :blockarg => "&", :brace_block => :lbrace, :break => "break", :case => "case", :class => "class", :def => "def", :defined => "defined?", :defs => "def", :do_block => "do", :else => "else", :elsif => "elsif", :ensure => "ensure", :for => "for", :hash => :lbrace, :if => "if", :lambda => [:tlambda, "lambda"], :module => "module", :next => "next", :paren => :lparen, :qwords_literal => :qwords_beg, :redo => "redo", :regexp_literal => :regexp_beg, :rescue => "rescue", :rest_param => "*", :retry => "retry", :return => "return", :return0 => "return", :sclass => "class", :string_embexpr => :embexpr_beg, :string_literal => [:tstring_beg, :heredoc_beg], :super => "super", :symbol => :symbeg, :top_const_ref => "::", :undef => "undef", :unless => "unless", :until => "until", :when => "when", :while => "while", :xstring_literal => :backtick, :yield => "yield", :yield0 => "yield", :zsuper => "super" } REV_MAPPINGS = {} AST_TOKENS = [:CHAR, :backref, :const, :cvar, :gvar, :heredoc_end, :ident, :int, :float, :ivar, :label, :period, :regexp_end, :tstring_content, :backtick] MAPPINGS.each do |k, v| if Array === v v.each {|_v| (REV_MAPPINGS[_v] ||= []) << k } else (REV_MAPPINGS[v] ||= []) << k end end PARSER_EVENT_TABLE.each do |event, arity| node_class = AstNode.node_class_for(event) if /_new\z/ =~ event.to_s and arity == 0 module_eval(<<-eof, __FILE__, __LINE__ + 1) def on_#{event}(*args) #{node_class}.new(:list, args, :listchar => charno...charno, :listline => lineno..lineno) end eof elsif /_add(_.+)?\z/ =~ event.to_s module_eval(<<-eof, __FILE__, __LINE__ + 1) begin; undef on_#{event}; rescue NameError; end def on_#{event}(list, item) list.push(item) list end eof elsif MAPPINGS.has_key?(event) module_eval(<<-eof, __FILE__, __LINE__ + 1) begin; undef on_#{event}; rescue NameError; end def on_#{event}(*args) visit_event #{node_class}.new(:#{event}, args) end eof else module_eval(<<-eof, __FILE__, __LINE__ + 1) begin; undef on_#{event}; rescue NameError; end def on_#{event}(*args) #{node_class}.new(:#{event}, args, :listline => lineno..lineno, :listchar => charno...charno) end eof end end SCANNER_EVENTS.each do |event| ast_token = AST_TOKENS.include?(event) module_eval(<<-eof, __FILE__, __LINE__ + 1) begin; undef on_#{event}; rescue NameError; end def on_#{event}(tok) visit_ns_token(:#{event}, tok, #{ast_token.inspect}) end eof end REV_MAPPINGS.select {|k,v| k.is_a?(Symbol) }.each do |pair| event, value = *pair ast_token = AST_TOKENS.include?(event) module_eval(<<-eof, __FILE__, __LINE__ + 1) begin; undef on_#{event}; rescue NameError; end def on_#{event}(tok) (@map[:#{event}] ||= []) << [lineno, charno] visit_ns_token(:#{event}, tok, #{ast_token.inspect}) end eof end [:kw, :op].each do |event| module_eval(<<-eof, __FILE__, __LINE__ + 1) begin; undef on_#{event}; rescue NameError; end def on_#{event}(tok) unless @last_ns_token == [:kw, "def"] || (@tokens.last && @tokens.last[0] == :symbeg) (@map[tok] ||= []) << [lineno, charno] end visit_ns_token(:#{event}, tok, true) end eof end [:sp, :nl, :ignored_nl].each do |event| module_eval(<<-eof, __FILE__, __LINE__ + 1) begin; undef on_#{event}; rescue NameError; end def on_#{event}(tok) add_token(:#{event}, tok) @charno += tok.length end eof end def visit_event(node) map = @map[MAPPINGS[node.type]] lstart, sstart = *(map ? map.pop : [lineno, @ns_charno - 1]) node.source_range = Range.new(sstart, @ns_charno - 1) node.line_range = Range.new(lstart, lineno) if node.respond_to?(:block) sr, lr = node.block.source_range, node.block.line_range node.block.source_range = Range.new(sr.first, @tokens.last[2][1]) node.block.line_range = Range.new(lr.first, @tokens.last[2][0]) end node end def visit_event_arr(node) mapping = MAPPINGS[node.type].find {|k| @map[k] && !@map[k].empty? } lstart, sstart = *@map[mapping].pop node.source_range = Range.new(sstart, @ns_charno - 1) node.line_range = Range.new(lstart, lineno) node end def visit_ns_token(token, data, ast_token = false) add_token(token, data) ch = charno @last_ns_token = [token, data] @charno += data.length @ns_charno = charno if ast_token AstNode.new(token, [data], :line => lineno..lineno, :char => ch..charno-1, :token => true) end end def add_token(token, data) if @tokens.last && @tokens.last[0] == :symbeg @tokens[-1] = [:symbol, ":" + data, @tokens.last[2]] elsif @heredoc_state == :started @heredoc_tokens << [token, data, [lineno, charno]] # fix ripper encoding of heredoc bug # (see http://bugs.ruby-lang.org/issues/6200) data.force_encoding(file_encoding) if file_encoding @heredoc_state = :ended if token == :heredoc_end elsif (token == :nl || token == :comment) && @heredoc_state == :ended @heredoc_tokens.unshift([token, data, [lineno, charno]]) @tokens += @heredoc_tokens @heredoc_tokens = nil @heredoc_state = nil else @tokens << [token, data, [lineno, charno]] if token == :heredoc_beg @heredoc_state = :started @heredoc_tokens = [] end end end undef on_program undef on_assoc_new undef on_array undef on_hash undef on_bare_assoc_hash undef on_assoclist_from_args undef on_aref undef on_aref_field undef on_lbracket undef on_rbracket undef on_qwords_new undef on_qwords_add undef on_string_literal undef on_lambda undef on_unary undef on_string_content undef on_rescue undef on_void_stmt undef on_params undef on_label undef on_comment undef on_embdoc_beg undef on_embdoc undef on_embdoc_end undef on_parse_error undef on_bodystmt undef on_top_const_ref undef on_const_path_ref def on_program(*args) args.first end def on_body_stmt(*args) args.compact.size == 1 ? args.first : AstNode.new(:list, args) end alias on_bodystmt on_body_stmt def on_assoc_new(*args) AstNode.new(:assoc, args) end def on_hash(*args) visit_event AstNode.new(:hash, args.first || []) end def on_bare_assoc_hash(*args) AstNode.new(:list, args.first) end def on_assoclist_from_args(*args) args.first end def on_unary(op, val) map = @map[op.to_s[0,1]] lstart, sstart = *(map ? map.pop : [lineno, @ns_charno - 1]) node = AstNode.node_class_for(:unary).new(:unary, [op, val]) node.source_range = Range.new(sstart, @ns_charno - 1) node.line_range = Range.new(lstart, lineno) node end def on_aref(*args) @map[:lbracket].pop ll, lc = *@map[:aref].pop sr = args.first.source_range.first..lc lr = args.first.line_range.first..ll AstNode.new(:aref, args, :char => sr, :line => lr) end def on_aref_field(*args) @map[:lbracket].pop AstNode.new(:aref_field, args, :listline => lineno..lineno, :listchar => charno...charno) end def on_array(other) node = AstNode.node_class_for(:array).new(:array, [other]) map = @map[MAPPINGS[node.type]] if map && !map.empty? lstart, sstart = *map.pop node.source_range = Range.new(sstart, @ns_charno - 1) node.line_range = Range.new(lstart, lineno) else sstart = other.source_range.begin lstart = other.line_range.begin node.source_range = Range.new(sstart, @ns_charno - 1) node.line_range = Range.new(lstart, lineno) node.source_range = other.source_range node.line_range = other.line_range end node end def on_lbracket(tok) (@map[:lbracket] ||= []) << [lineno, charno] visit_ns_token(:lbracket, tok, false) end def on_rbracket(tok) (@map[:aref] ||= []) << [lineno, charno] visit_ns_token(:rbracket, tok, false) end def on_top_const_ref(*args) type = :top_const_ref node = AstNode.node_class_for(type).new(type, args) mapping = @map[MAPPINGS[type]] extra_op = mapping.last[1] + 2 == charno ? mapping.pop : nil lstart, sstart = *mapping.pop node.source_range = Range.new(sstart, args.last.source_range.last) node.line_range = Range.new(lstart, args.last.line_range.last) mapping.push(extra_op) if extra_op node end def on_const_path_ref(*args) ReferenceNode.new(:const_path_ref, args, :listline => lineno..lineno, :listchar => charno..charno) end [:if_mod, :unless_mod, :while_mod].each do |kw| node_class = AstNode.node_class_for(kw) module_eval(<<-eof, __FILE__, __LINE__ + 1) begin; undef on_#{kw}; rescue NameError; end def on_#{kw}(*args) sr = args.last.source_range.first..args.first.source_range.last lr = args.last.line_range.first..args.first.line_range.last #{node_class}.new(:#{kw}, args, :line => lr, :char => sr) end eof end def on_qwords_new(*args) node = LiteralNode.new(:qwords_literal, args) if @map[:qwords_beg] lstart, sstart = *@map[:qwords_beg].pop node.source_range = Range.new(sstart, @ns_charno-1) node.line_range = Range.new(lstart, lineno) end node end def on_qwords_add(list, item) last = @source[@ns_charno,1] == "\n" ? @ns_charno - 1 : @ns_charno list.source_range = (list.source_range.first..last) list.line_range = (list.line_range.first..lineno) list.push(item) list end def on_string_literal(*args) node = visit_event_arr(LiteralNode.new(:string_literal, args)) if args.size == 1 r = args[0].source_range if node.source_range != Range.new(r.first - 1, r.last + 1) klass = AstNode.node_class_for(node[0].type) r = Range.new(node.source_range.first + 1, node.source_range.last - 1) node[0] = klass.new(node[0].type, [@source[r]], :line => node.line_range, :char => r) end end node end def on_lambda(*args) visit_event_arr AstNode.new(:lambda, args) end def on_string_content(*args) AstNode.new(:string_content, args, :listline => lineno..lineno, :listchar => charno..charno) end def on_rescue(exc, *args) exc = AstNode.new(:list, exc) if exc visit_event AstNode.new(:rescue, [exc, *args]) end def on_void_stmt AstNode.new(:void_stmt, [], :line => lineno..lineno, :char => charno...charno) end def on_params(*args) args.map! do |arg| if arg.class == Array if arg.first.class == Array arg.map! do |sub_arg| if sub_arg.class == Array AstNode.new(:default_arg, sub_arg, :listline => lineno..lineno, :listchar => charno..charno) else sub_arg end end end AstNode.new(:list, arg, :listline => lineno..lineno, :listchar => charno..charno) else arg end end ParameterNode.new(:params, args, :listline => lineno..lineno, :listchar => charno..charno) end def on_label(data) add_token(:label, data) ch = charno @charno += data.length @ns_charno = charno AstNode.new(:label, [data[0...-1]], :line => lineno..lineno, :char => ch..charno-1, :token => true) end def on_comment(comment) not_comment = false if @last_ns_token.nil? || @last_ns_token.size == 0 if comment =~ SourceParser::SHEBANG_LINE && !@encoding_line @shebang_line = comment not_comment = true elsif comment =~ SourceParser::ENCODING_LINE @encoding_line = comment not_comment = true end end ch = charno visit_ns_token(:comment, comment) if not_comment @last_ns_token = nil return end source_range = ch..(charno-1) comment = comment.gsub(/^(\#+)\s{0,1}/, '').chomp append_comment = @comments[lineno - 1] hash_flag = $1 == '##' ? true : false if append_comment && @comments_last_column && @comments_last_column == column @comments.delete(lineno - 1) @comments_flags[lineno] = @comments_flags[lineno - 1] @comments_flags.delete(lineno - 1) range = @comments_range.delete(lineno - 1) source_range = range.first..source_range.last comment = append_comment + "\n" + comment end @comments[lineno] = comment @comments_range[lineno] = source_range @comments_flags[lineno] = hash_flag if !append_comment @comments_last_column = column end def on_embdoc_beg(text) visit_ns_token(:embdoc_beg, text) @embdoc_start = charno-text.length @embdoc = "" end def on_embdoc(text) visit_ns_token(:embdoc, text) @embdoc << text end def on_embdoc_end(text) visit_ns_token(:embdoc_end, text) @comments_last_column = nil @comments[lineno] = @embdoc @comments_range[lineno] = @embdoc_start...charno @embdoc_start = nil @embdoc = nil end def on_parse_error(msg) raise ParserSyntaxError, "syntax error in `#{file}`:(#{lineno},#{column}): #{msg}" end def insert_comments root.traverse do |node| next if node.type == :comment || node.type == :list || node.parent.type != :list # check upwards from line before node; check node's line at the end ((node.line-1).downto(node.line-2).to_a + [node.line]).each do |line| comment = @comments[line] if comment && !comment.empty? add_comment(line, node) break end end @comments.keys.each do |line| if node.line > line add_comment(line, nil, node) end end end # insert any lone unadded comments before node root.traverse do |node| next if node.type == :list || node.parent.type != :list @comments.keys.each do |line| if node.line_range.include?(line) pick = nil node.traverse do |subnode| next unless subnode.type == :list pick ||= subnode next unless subnode.line_range.include?(line) pick = subnode end add_comment(line, nil, pick, true) if pick end end end if @comments.size > 0 # insert all remaining comments @comments.each do |line, comment| add_comment(line, nil, root, true) end @comments = {} end def add_comment(line, node = nil, before_node = nil, into = false) comment = @comments[line] source_range = @comments_range[line] line_range = ((line - comment.count("\n"))..line) if node.nil? node = CommentNode.new(:comment, [comment], :line => line_range, :char => source_range) if into before_node.push(node) before_node.unfreeze node.parent = before_node elsif before_node parent_node = before_node.parent idx = parent_node.index(before_node) parent_node.insert(idx, node) parent_node.unfreeze node.parent = parent_node end end node.docstring = comment node.docstring_hash_flag = @comments_flags[line] node.docstring_range = line_range @comments.delete(line) @comments_range.delete(line) @comments_flags.delete(line) end def freeze_tree(node = nil) node ||= root node.children.each do |child| child.parent = node freeze_tree(child) end end end if defined?(::Ripper) end end endyard-0.8.7.3/lib/yard/parser/ruby/legacy/0000755000004100000410000000000012261240652020104 5ustar www-datawww-datayard-0.8.7.3/lib/yard/parser/ruby/legacy/ruby_parser.rb0000644000004100000410000000117412261240652022771 0ustar www-datawww-datamodule YARD module Parser module Ruby module Legacy # Legacy Ruby parser # @since 0.5.6 class RubyParser < Parser::Base def initialize(source, filename) @source = source end def parse @parse ||= StatementList.new(@source) self end def tokenize @tokenize ||= TokenList.new(@source) end def enumerator @parse end def encoding_line; @parse.encoding_line end def shebang_line; @parse.shebang_line end end end end end endyard-0.8.7.3/lib/yard/parser/ruby/legacy/statement_list.rb0000644000004100000410000003122212261240652023470 0ustar www-datawww-datamodule YARD module Parser::Ruby::Legacy class StatementList < Array include RubyToken attr_accessor :shebang_line, :encoding_line # The following list of tokens will require a block to be opened # if used at the beginning of a statement. OPEN_BLOCK_TOKENS = [TkCLASS, TkDEF, TkMODULE, TkUNTIL, TkIF, TkELSIF, TkUNLESS, TkWHILE, TkFOR, TkCASE] # Creates a new statement list # # @param [TokenList, String] content the tokens to create the list from def initialize(content) @shebang_line = nil @encoding_line = nil if content.is_a? TokenList @tokens = content.dup elsif content.is_a? String @tokens = TokenList.new(content.gsub("\r", "")) else raise ArgumentError, "Invalid content for StatementList: #{content.inspect}:#{content.class}" end parse_statements end private def parse_statements while stmt = next_statement do self << stmt end end # Returns the next statement in the token stream # # @return [Statement] the next statement def next_statement @state = :first_statement @statement_stack = [] @level = 0 @block_num = 0 @done = false @current_block = nil @comments_line = nil @comments_hash_flag = nil @statement, @block, @comments = TokenList.new, nil, nil @last_tk, @last_ns_tk, @before_last_tk, @before_last_ns_tk = nil, nil, nil, nil @first_line = nil while !@done && tk = @tokens.shift process_token(tk) @before_last_tk = @last_tk @last_tk = tk # Save last token unless [TkSPACE, TkNL, TkEND_OF_SCRIPT].include? tk.class @before_last_ns_tk = @last_ns_tk @last_ns_tk = tk end end # Return the code block with starting token and initial comments # If there is no code in the block, return nil @comments = @comments.compact if @comments if @block || !@statement.empty? sanitize_statement_end sanitize_block @statement.pop if [TkNL, TkSPACE, TkSEMICOLON].include?(@statement.last.class) stmt = Statement.new(@statement, @block, @comments) if @comments && @comments_line stmt.comments_range = (@comments_line..(@comments_line + @comments.size - 1)) stmt.comments_hash_flag = @comments_hash_flag end stmt elsif @comments @statement << TkCOMMENT.new(@comments_line, 0) @statement.first.set_text("# " + @comments.join("\n# ")) Statement.new(@statement, nil, @comments) else nil end end def sanitize_statement_end extra = [] (@statement.size - 1).downto(0) do |index| token = @statement[index] if TkStatementEnd === token while [TkNL, TkSPACE, TkSEMICOLON].include?(@statement[index - 1].class) extra.unshift(@statement.delete_at(index - 1)) index -= 1 end @statement.insert(index + 1, *extra) return end end end def sanitize_block return unless @block extra = [] while [TkSPACE, TkNL, TkSEMICOLON].include?(@block.last.class) next(@block.pop) if TkSEMICOLON === @block.last extra.unshift(@block.pop) end @statement.each_with_index do |token, index| if TkBlockContents === token @statement[index, 1] = [token, *extra] return end end end # Processes a single token # # @param [RubyToken::Token] tk the token to process def process_token(tk) # p tk.class, tk.text, @state, @level, @current_block, "
            " case @state when :first_statement return if process_initial_comment(tk) return if @statement.empty? && [TkSPACE, TkNL, TkCOMMENT].include?(tk.class) @comments_last_line = nil if @statement.empty? && tk.class == TkALIAS @state = :alias_statement @alias_values = [] push_token(tk) return end return if process_simple_block_opener(tk) push_token(tk) return if process_complex_block_opener(tk) if balances?(tk) process_statement_end(tk) else @state = :balance end when :alias_statement push_token(tk) @alias_values << tk unless [TkSPACE, TkNL, TkCOMMENT].include?(tk.class) if @alias_values.size == 2 @state = :first_statement if [NilClass, TkNL, TkEND_OF_SCRIPT, TkSEMICOLON].include?(peek_no_space.class) @done = true end end when :balance @statement << tk return unless balances?(tk) @state = :first_statement process_statement_end(tk) when :block_statement push_token(tk) return unless balances?(tk) process_statement_end(tk) when :pre_block @current_block = nil process_block_token(tk) unless tk.class == TkSEMICOLON @state = :block when :block process_block_token(tk) when :post_block if tk.class == TkSPACE @statement << tk return end process_statement_end(tk) @state = :block end if @first_line == tk.line_no && !@statement.empty? && TkCOMMENT === tk process_initial_comment(tk) end end # Processes a token in a block # # @param [RubyToken::Token] tk the token to process def process_block_token(tk) if balances?(tk) @statement << tk @state = :first_statement process_statement_end(tk) elsif @block_num > 1 || (@block.empty? && [TkSPACE, TkNL].include?(tk.class)) @statement << tk else if @block.empty? @statement << TkBlockContents.new(tk.line_no, tk.char_no) end @block << tk end end # Processes a comment token that comes before a statement # # @param [RubyToken::Token] tk the token to process # @return [Boolean] whether or not +tk+ was processed as an initial comment def process_initial_comment(tk) if @statement.empty? && (@comments_last_line || 0) < tk.line_no - 2 @comments = nil end return unless tk.class == TkCOMMENT case tk.text when Parser::SourceParser::SHEBANG_LINE if !@last_ns_tk && !@encoding_line @shebang_line = tk.text return end when Parser::SourceParser::ENCODING_LINE if (@last_ns_tk.class == TkCOMMENT && @last_ns_tk.text == @shebang_line) || !@last_ns_tk @encoding_line = tk.text return end end return if !@statement.empty? && @comments return if @first_line && tk.line_no > @first_line if @comments_last_line && @comments_last_line < tk.line_no - 1 if @comments && @statement.empty? @tokens.unshift(tk) return @done = true end @comments = nil end @comments_line = tk.line_no unless @comments # Remove the "#" and up to 1 space before the text # Since, of course, the convention is to have "# text" # and not "#text", which I deem ugly (you heard it here first) @comments ||= [] if tk.text =~ /\A=begin/ lines = tk.text.count("\n") @comments += tk.text.gsub(/\A=begin.*\r?\n|\r?\n=end.*\r?\n?\Z/, '').split(/\r?\n/) @comments_last_line = tk.line_no + lines else @comments << tk.text.gsub(/^(#+)\s{0,1}/, '') @comments_hash_flag = $1 == '##' if @comments_hash_flag == nil @comments_last_line = tk.line_no end @comments.pop if @comments.size == 1 && @comments.first =~ /^\s*$/ true end # Processes a simple block-opening token; # that is, a block opener such as +begin+ or +do+ # that isn't followed by an expression # # @param [RubyToken::Token] tk the token to process def process_simple_block_opener(tk) return unless [TkLBRACE, TkDO, TkBEGIN, TkELSE].include?(tk.class) && # Make sure hashes are parsed as hashes, not as blocks (@last_ns_tk.nil? || @last_ns_tk.lex_state != EXPR_BEG) @level += 1 @state = :block @block_num += 1 unless @block @block = TokenList.new tokens = [tk, TkStatementEnd.new(tk.line_no, tk.char_no)] tokens = tokens.reverse if TkBEGIN === tk.class @statement.push(*tokens) else @statement << tk end true end # Processes a complex block-opening token; # that is, a block opener such as +while+ or +for+ # that is followed by an expression # # @param [RubyToken::Token] tk the token to process def process_complex_block_opener(tk) return unless OPEN_BLOCK_TOKENS.include?(tk.class) @current_block = tk.class @state = :block_statement true end # Processes a token that closes a statement # # @param [RubyToken::Token] tk the token to process def process_statement_end(tk) # Whitespace means that we keep the same value of @new_statement as last token return if tk.class == TkSPACE return unless # We might be coming after a statement-ending token... ((@last_tk && [TkSEMICOLON, TkNL, TkEND_OF_SCRIPT].include?(tk.class)) || # Or we might be at the beginning of an argument list (@current_block == TkDEF && tk.class == TkRPAREN)) # Continue line ending on . or :: return if @last_tk && [EXPR_DOT].include?(@last_tk.lex_state) # Continue a possible existing new statement unless we just finished an expression... return unless (@last_tk && [EXPR_END, EXPR_ARG].include?(@last_tk.lex_state)) || # Or we've opened a block and are ready to move into the body (@current_block && [TkNL, TkSEMICOLON].include?(tk.class) && # Handle the case where the block statement's expression is on the next line # # while # foo # end @last_ns_tk.class != @current_block && # And the case where part of the expression is on the next line # # while foo || # bar # end @last_tk.lex_state != EXPR_BEG) # Continue with the statement if we've hit a comma in a def return if @current_block == TkDEF && peek_no_space.class == TkCOMMA if [TkEND_OF_SCRIPT, TkNL, TkSEMICOLON].include?(tk.class) && @state == :block_statement && [TkRBRACE, TkEND].include?(@last_ns_tk.class) && @level == 0 @current_block = nil end unless @current_block @done = true return end @state = :pre_block @level += 1 @block_num += 1 unless @block @block = TokenList.new @statement << TkStatementEnd.new(tk.line_no, tk.char_no) end end # Handles the balancing of parentheses and blocks # # @param [RubyToken::Token] tk the token to process # @return [Boolean] whether or not the current statement's parentheses and blocks # are balanced after +tk+ def balances?(tk) unless [TkALIAS, TkDEF].include?(@last_ns_tk.class) || @before_last_ns_tk.class == TkALIAS if [TkLPAREN, TkLBRACK, TkLBRACE, TkDO, TkBEGIN].include?(tk.class) @level += 1 elsif OPEN_BLOCK_TOKENS.include?(tk.class) @level += 1 unless tk.class == TkELSIF elsif [TkRPAREN, TkRBRACK, TkRBRACE, TkEND].include?(tk.class) && @level > 0 @level -= 1 end end @level == 0 end # Adds a token to the current statement, # unless it's a newline, semicolon, or comment # # @param [RubyToken::Token] tk the token to process def push_token(tk) @first_line = tk.line_no if @statement.empty? @statement << tk unless @level == 0 && [TkCOMMENT].include?(tk.class) end # Returns the next token in the stream that's not a space # # @return [RubyToken::Token] the next non-space token def peek_no_space return @tokens.first unless @tokens.first.class == TkSPACE return @tokens[1] end end end end yard-0.8.7.3/lib/yard/parser/ruby/legacy/token_list.rb0000644000004100000410000000367212261240652022614 0ustar www-datawww-datamodule YARD module Parser::Ruby::Legacy class TokenList < Array include RubyToken def initialize(content = nil) self << content if content end def to_s(full_statement = false, show_block = true) inject([]) do |acc, token| break acc if !full_statement && TkStatementEnd === token if !show_block && TkBlockContents === token acc << "" else acc << token.text end acc end.join end # @param [TokenList, Token, String] tokens # A list of tokens. If the token is a string, it # is parsed with {RubyLex}. def push(*tokens) tokens.each do |tok| if tok.is_a?(TokenList) || tok.is_a?(Array) concat tok elsif tok.is_a?(Token) super tok elsif tok.is_a?(String) parse_content(tok) else raise ArgumentError, "Expecting token, list of tokens or string of code to be tokenized. Got #{tok.class}" end end self end alias_method :<<, :push def squeeze(type = TkSPACE) last = nil TokenList.new(map {|t| x = t.is_a?(type) && last.is_a?(type) ? nil : t; last = t; x }) end private def parse_content(content) lex = RubyLex.new(content) while tk = lex.token do self << convert_token(lex, tk) end end def convert_token(lex, tk) if TkIDENTIFIER === tk && lex.peek == ':' next_tk = lex.token sym = TkLABEL.new(tk.line_no, tk.char_no, nil) sym.lex_state = lex.lex_state sym.set_text(tk.text + next_tk.text) elsif TkSYMBEG === tk && next_tk = lex.token sym = TkSYMBOL.new(tk.line_no, tk.char_no, nil) sym.lex_state = lex.lex_state sym.set_text(tk.text + next_tk.text) else tk end end end end endyard-0.8.7.3/lib/yard/parser/ruby/legacy/statement.rb0000644000004100000410000000300112261240652022427 0ustar www-datawww-datamodule YARD module Parser::Ruby::Legacy class Statement attr_reader :tokens, :comments, :block attr_accessor :comments_range # @deprecated Groups are now defined by directives # @see Tags::GroupDirective attr_accessor :group attr_accessor :comments_hash_flag def initialize(tokens, block = nil, comments = nil) @tokens = tokens @block = block @comments = comments @comments_hash_flag = false end def first_line to_s.split(/\n/)[0] end def to_s(include_block = true) tokens.map do |token| RubyToken::TkBlockContents === token ? (include_block ? block.to_s : '') : token.text end.join end alias source to_s def inspect l = line - 1 to_s(false).split(/\n/).map do |text| "\t#{l += 1}: #{text}" end.join("\n") end def show "\t#{line}: #{first_line}" end # @return [Fixnum] the first line of Ruby source def line tokens.first.line_no end # @return [Range] the first to last lines of Ruby source # @since 0.5.4 def line_range tokens.first.line_no..tokens.last.line_no end private def clean_tokens(tokens) last_tk = nil tokens.reject do |tk| tk.is_a?(RubyToken::TkNL) || (last_tk.is_a?(RubyToken::TkSPACE) && last_tk.class == tk.class) && last_tk = tk end end end end endyard-0.8.7.3/lib/yard/parser/ruby/legacy/ruby_lex.rb0000644000004100000410000010645312261240652022273 0ustar www-datawww-datarequire "e2mmap" require "irb/slex" module YARD module Parser::Ruby::Legacy # Legacy lexical tokenizer module. module RubyToken EXPR_BEG = :EXPR_BEG EXPR_MID = :EXPR_MID EXPR_END = :EXPR_END EXPR_ARG = :EXPR_ARG EXPR_FNAME = :EXPR_FNAME EXPR_DOT = :EXPR_DOT EXPR_CLASS = :EXPR_CLASS # Represents a token in the Ruby lexer class Token # @return [Integer] the line number in the file/stream the token is # located. attr_reader :line_no # @return [Integer] the character number in the file/stream the token # is located. attr_reader :char_no # @return [String] the token text value attr_reader :text # @return [Symbol] the lexical state at the token attr_accessor :lex_state # @private NO_TEXT = "??".freeze # Creates a new Token object # @param [Integer] line_no the line number to initialize the token to # @param [Integer] char_no the char number to initialize the token to def initialize(line_no, char_no) @line_no = line_no @char_no = char_no @text = NO_TEXT end # Chainable way to sets the text attribute # # @param [String] text the new text # @return [Token] this token object def set_text(text) @text = text self end end # Represents a block class TkBlockContents < Token def text; '...' end end # Represents an end statement class TkStatementEnd < Token def text; '' end end class TkNode < Token attr :node end # Represents whitespace class TkWhitespace < Token end # Represents a Ruby identifier class TkId < Token def initialize(line_no, char_no, name) super(line_no, char_no) @name = name end attr :name end # Represents a Ruby keyword class TkKW < TkId end # Represents a Ruby value class TkVal < Token def initialize(line_no, char_no, value = nil) super(line_no, char_no) set_text(value) end end class TkOp < Token def name self.class.op_name end end class TkOPASGN < TkOp def initialize(line_no, char_no, op) super(line_no, char_no) op = TkReading2Token[op] unless op.kind_of?(Symbol) @op = op end attr :op end class TkUnknownChar < Token def initialize(line_no, char_no, id) super(line_no, char_no) @name = char_no > 255 ? '?' : char_no.chr end attr :name end class TkError < Token end # @private def set_token_position(line, char) @prev_line_no = line @prev_char_no = char end # @private def Token(token, value = nil) tk = nil case token when String, Symbol source = token.kind_of?(String) ? TkReading2Token : TkSymbol2Token if (tk = source[token]).nil? IRB.fail TkReading2TokenNoKey, token end tk = Token(tk[0], value) else if token tk = if (token.ancestors & [TkId, TkVal, TkOPASGN, TkUnknownChar]).empty? token.new(@prev_line_no, @prev_char_no) else token.new(@prev_line_no, @prev_char_no, value) end end end tk end # @private TokenDefinitions = [ [:TkCLASS, TkKW, "class", EXPR_CLASS], [:TkMODULE, TkKW, "module", EXPR_BEG], [:TkDEF, TkKW, "def", EXPR_FNAME], [:TkUNDEF, TkKW, "undef", EXPR_FNAME], [:TkBEGIN, TkKW, "begin", EXPR_BEG], [:TkRESCUE, TkKW, "rescue", EXPR_MID], [:TkENSURE, TkKW, "ensure", EXPR_BEG], [:TkEND, TkKW, "end", EXPR_END], [:TkIF, TkKW, "if", EXPR_BEG, :TkIF_MOD], [:TkUNLESS, TkKW, "unless", EXPR_BEG, :TkUNLESS_MOD], [:TkTHEN, TkKW, "then", EXPR_BEG], [:TkELSIF, TkKW, "elsif", EXPR_BEG], [:TkELSE, TkKW, "else", EXPR_BEG], [:TkCASE, TkKW, "case", EXPR_BEG], [:TkWHEN, TkKW, "when", EXPR_BEG], [:TkWHILE, TkKW, "while", EXPR_BEG, :TkWHILE_MOD], [:TkUNTIL, TkKW, "until", EXPR_BEG, :TkUNTIL_MOD], [:TkFOR, TkKW, "for", EXPR_BEG], [:TkBREAK, TkKW, "break", EXPR_END], [:TkNEXT, TkKW, "next", EXPR_END], [:TkREDO, TkKW, "redo", EXPR_END], [:TkRETRY, TkKW, "retry", EXPR_END], [:TkIN, TkKW, "in", EXPR_BEG], [:TkDO, TkKW, "do", EXPR_BEG], [:TkRETURN, TkKW, "return", EXPR_MID], [:TkYIELD, TkKW, "yield", EXPR_END], [:TkSUPER, TkKW, "super", EXPR_END], [:TkSELF, TkKW, "self", EXPR_END], [:TkNIL, TkKW, "nil", EXPR_END], [:TkTRUE, TkKW, "true", EXPR_END], [:TkFALSE, TkKW, "false", EXPR_END], [:TkAND, TkKW, "and", EXPR_BEG], [:TkOR, TkKW, "or", EXPR_BEG], [:TkNOT, TkKW, "not", EXPR_BEG], [:TkIF_MOD, TkKW], [:TkUNLESS_MOD, TkKW], [:TkWHILE_MOD, TkKW], [:TkUNTIL_MOD, TkKW], [:TkALIAS, TkKW, "alias", EXPR_FNAME], [:TkDEFINED, TkKW, "defined?", EXPR_END], [:TklBEGIN, TkKW, "BEGIN", EXPR_END], [:TklEND, TkKW, "END", EXPR_END], [:Tk__LINE__, TkKW, "__LINE__", EXPR_END], [:Tk__FILE__, TkKW, "__FILE__", EXPR_END], [:TkIDENTIFIER, TkId], [:TkFID, TkId], [:TkGVAR, TkId], [:TkIVAR, TkId], [:TkCONSTANT, TkId], [:TkINTEGER, TkVal], [:TkFLOAT, TkVal], [:TkSYMBOL, TkVal], [:TkLABEL, TkVal], [:TkSTRING, TkVal], [:TkXSTRING, TkVal], [:TkREGEXP, TkVal], [:TkCOMMENT, TkVal], [:TkDSTRING, TkNode], [:TkDXSTRING, TkNode], [:TkDREGEXP, TkNode], [:TkNTH_REF, TkId], [:TkBACK_REF, TkId], [:TkUPLUS, TkOp, "+@"], [:TkUMINUS, TkOp, "-@"], [:TkPOW, TkOp, "**"], [:TkCMP, TkOp, "<=>"], [:TkEQ, TkOp, "=="], [:TkEQQ, TkOp, "==="], [:TkNEQ, TkOp, "!="], [:TkGEQ, TkOp, ">="], [:TkLEQ, TkOp, "<="], [:TkANDOP, TkOp, "&&"], [:TkOROP, TkOp, "||"], [:TkMATCH, TkOp, "=~"], [:TkNMATCH, TkOp, "!~"], [:TkDOT2, TkOp, ".."], [:TkDOT3, TkOp, "..."], [:TkAREF, TkOp, "[]"], [:TkASET, TkOp, "[]="], [:TkLSHFT, TkOp, "<<"], [:TkRSHFT, TkOp, ">>"], [:TkCOLON2, TkOp], [:TkCOLON3, TkOp], [:OPASGN, TkOp], # +=, -= etc. # [:TkASSOC, TkOp, "=>"], [:TkQUESTION, TkOp, "?"], #? [:TkCOLON, TkOp, ":"], #: # [:TkfLPAREN], # func( # # [:TkfLBRACK], # func[ # # [:TkfLBRACE], # func{ # [:TkSTAR], # *arg [:TkAMPER], # &arg # # [:TkSYMBOL, TkId], # :SYMBOL [:TkSYMBEG, TkId], [:TkGT, TkOp, ">"], [:TkLT, TkOp, "<"], [:TkPLUS, TkOp, "+"], [:TkMINUS, TkOp, "-"], [:TkMULT, TkOp, "*"], [:TkDIV, TkOp, "/"], [:TkMOD, TkOp, "%"], [:TkBITOR, TkOp, "|"], [:TkBITXOR, TkOp, "^"], [:TkBITAND, TkOp, "&"], [:TkBITNOT, TkOp, "~"], [:TkNOTOP, TkOp, "!"], [:TkBACKQUOTE, TkOp, "`"], [:TkASSIGN, Token, "="], [:TkDOT, Token, "."], [:TkLPAREN, Token, "("], #(exp) [:TkLBRACK, Token, "["], #[arry] [:TkLBRACE, Token, "{"], #{hash} [:TkRPAREN, Token, ")"], [:TkRBRACK, Token, "]"], [:TkRBRACE, Token, "}"], [:TkCOMMA, Token, ","], [:TkSEMICOLON, Token, ";"], # [:TkRD_COMMENT, TkVal], [:TkSPACE, TkWhitespace], [:TkNL, TkWhitespace], [:TkEND_OF_SCRIPT, TkWhitespace], [:TkBACKSLASH, TkUnknownChar, "\\"], [:TkAT, TkUnknownChar, "@"], [:TkDOLLAR, TkUnknownChar, "\$"], #" ] # { reading => token_class } # { reading => [token_class, *opt] } TkReading2Token = {} TkSymbol2Token = {} # @private def RubyToken.def_token(token_n, super_token = Token, reading = nil, *opts) token_n = token_n.id2name unless token_n.kind_of?(String) if RubyToken.const_defined?(token_n) # IRB.fail AlreadyDefinedToken, token_n end token_c = Class.new super_token RubyToken.const_set token_n, token_c # token_c.inspect if reading if TkReading2Token[reading] IRB.fail TkReading2TokenDuplicateError, token_n, reading end if opts.empty? TkReading2Token[reading] = [token_c] else TkReading2Token[reading] = [token_c].concat(opts) end end TkSymbol2Token[token_n.intern] = token_c if token_c <= TkOp token_c.class_eval %{ def self.op_name; "#{reading}"; end } end end for defs in TokenDefinitions def_token(*defs) end NEWLINE_TOKEN = TkNL.new(0,0) NEWLINE_TOKEN.set_text("\n") end # Lexical analyzer for Ruby source # @private class RubyLex # Read an input stream character by character. We allow for unlimited # ungetting of characters just read. # # We simplify the implementation greatly by reading the entire input # into a buffer initially, and then simply traversing it using # pointers. # # We also have to allow for the here document diversion. This # little gem comes about when the lexer encounters a here # document. At this point we effectively need to split the input # stream into two parts: one to read the body of the here document, # the other to read the rest of the input line where the here # document was initially encountered. For example, we might have # # do_something(<<-A, <<-B) # stuff # for # A # stuff # for # B # # When the lexer encounters the <= @size ch = @content[@offset, 1] @offset += 1 @hwm = @offset if @hwm < @offset if @newline_pending @line_num += 1 @last_newline = @offset - 1 @newline_pending = false end if ch == "\n" @newline_pending = true end ch end def getc_already_read getc end def ungetc(ch) raise "unget past beginning of file" if @offset <= 0 @offset -= 1 if @content[@offset] == ?\n @newline_pending = false end end def get_read res = @content[@read_back_offset...@offset] @read_back_offset = @offset res end def peek(at) pos = @offset + at if pos >= @size nil else @content[pos, 1] end end def peek_equal(str) @content[@offset, str.length] == str end def divert_read_from(reserve) @content[@offset, 0] = reserve @size = @content.size end end # end of nested class BufferedReader extend Exception2MessageMapper def_exception(:AlreadyDefinedToken, "Already defined token(%s)") def_exception(:TkReading2TokenNoKey, "key nothing(key='%s')") def_exception(:TkSymbol2TokenNoKey, "key nothing(key='%s')") def_exception(:TkReading2TokenDuplicateError, "key duplicate(token_n='%s', key='%s')") def_exception(:SyntaxError, "%s") include RubyToken include IRB attr_reader :continue attr_reader :lex_state def RubyLex.debug? false end def initialize(content) lex_init @reader = BufferedReader.new(content) @exp_line_no = @line_no = 1 @base_char_no = 0 @indent = 0 @ltype = nil @quoted = nil @lex_state = EXPR_BEG @space_seen = false @continue = false @line = "" @skip_space = false @read_auto_clean_up = false @exception_on_syntax_error = true end attr_accessor :skip_space attr_accessor :read_auto_clean_up attr_accessor :exception_on_syntax_error attr :indent # io functions def line_no @reader.line_num end def char_no @reader.column end def get_read @reader.get_read end def getc @reader.getc end def getc_of_rests @reader.getc_already_read end def gets c = getc or return l = "" begin l.concat c unless c == "\r" break if c == "\n" end while c = getc l end def ungetc(c = nil) @reader.ungetc(c) end def peek_equal?(str) @reader.peek_equal(str) end def peek(i = 0) @reader.peek(i) end def lex catch(:eof) do until (((tk = token).kind_of?(TkNL) || tk.kind_of?(TkEND_OF_SCRIPT)) && !@continue or tk.nil?) end line = get_read if line == "" and tk.kind_of?(TkEND_OF_SCRIPT) || tk.nil? nil else line end end end def token set_token_position(line_no, char_no) catch(:eof) do begin begin tk = @OP.match(self) @space_seen = tk.kind_of?(TkSPACE) rescue SyntaxError abort if @exception_on_syntax_error tk = TkError.new(line_no, char_no) end end while @skip_space and tk.kind_of?(TkSPACE) if @read_auto_clean_up get_read end # throw :eof unless tk p tk if $DEBUG tk.lex_state = lex_state if tk tk end end ENINDENT_CLAUSE = [ "case", "class", "def", "do", "for", "if", "module", "unless", "until", "while", "begin" #, "when" ] ACCEPTS_COLON = ["if", "for", "unless", "until", "while"] DEINDENT_CLAUSE = ["end" #, "when" ] PERCENT_LTYPE = { "q" => "\'", "Q" => "\"", "x" => "\`", "r" => "/", "w" => "]", "W" => "]" } PERCENT_PAREN = { "{" => "}", "[" => "]", "<" => ">", "(" => ")" } Ltype2Token = { "\'" => TkSTRING, "\"" => TkSTRING, "\`" => TkXSTRING, "/" => TkREGEXP, "]" => TkDSTRING } Ltype2Token.default = TkSTRING DLtype2Token = { "\"" => TkDSTRING, "\`" => TkDXSTRING, "/" => TkDREGEXP, } def lex_init() @OP = SLex.new @OP.def_rules("\0", "\004", "\032") do |chars, io| Token(TkEND_OF_SCRIPT).set_text(chars) end @OP.def_rules(" ", "\t", "\f", "\r", "\13") do |chars, io| @space_seen = TRUE while (ch = getc) =~ /[ \t\f\r\13]/ chars << ch end ungetc Token(TkSPACE).set_text(chars) end @OP.def_rule("#") do |op, io| identify_comment end @OP.def_rule("=begin", proc{@prev_char_no == 0 && peek(0) =~ /\s/}) do |op, io| str = op @ltype = "=" begin line = "" begin ch = getc line << ch end until ch == "\n" str << line end until line =~ /^=end/ ungetc @ltype = nil if str =~ /\A=begin\s+rdoc/i str.sub!(/\A=begin.*\n/, '') str.sub!(/^=end.*/m, '') Token(TkCOMMENT).set_text(str) else Token(TkCOMMENT).set_text(str) end end @OP.def_rule("\n") do print "\\n\n" if RubyLex.debug? @colonblock_seen = false case @lex_state when EXPR_BEG, EXPR_FNAME, EXPR_DOT @continue = TRUE else @continue = FALSE @lex_state = EXPR_BEG end Token(TkNL).set_text("\n") end @OP.def_rules("*", "**", "!", "!=", "!~", "=", "==", "===", "=~", "<=>", "<", "<=", ">", ">=", ">>") do |op, io| @lex_state = EXPR_BEG Token(op).set_text(op) end @OP.def_rules("<<") do |op, io| tk = nil if @lex_state != EXPR_END && @lex_state != EXPR_CLASS && (@lex_state != EXPR_ARG || @space_seen) c = peek(0) tk = identify_here_document if /[-\w_\"\'\`]/ =~ c end if !tk @lex_state = EXPR_BEG tk = Token(op).set_text(op) end tk end @OP.def_rules("'", '"') do |op, io| identify_string(op) end @OP.def_rules("`") do |op, io| if @lex_state == EXPR_FNAME Token(op).set_text(op) else identify_string(op) end end @OP.def_rules('?') do |op, io| if @lex_state == EXPR_END @lex_state = EXPR_BEG Token(TkQUESTION).set_text(op) else ch = getc if @lex_state == EXPR_ARG && ch !~ /\s/ ungetc @lex_state = EXPR_BEG Token(TkQUESTION).set_text(op) else str = op str << ch if (ch == '\\') #' str << read_escape end @lex_state = EXPR_END Token(TkINTEGER).set_text(str) end end end @OP.def_rules("&", "&&", "|", "||") do |op, io| @lex_state = EXPR_BEG Token(op).set_text(op) end @OP.def_rules("+=", "-=", "*=", "**=", "&=", "|=", "^=", "<<=", ">>=", "||=", "&&=") do |op, io| @lex_state = EXPR_BEG op =~ /^(.*)=$/ Token(TkOPASGN, $1).set_text(op) end @OP.def_rule("+@", proc{@lex_state == EXPR_FNAME}) do |op, io| Token(TkUPLUS).set_text(op) end @OP.def_rule("-@", proc{@lex_state == EXPR_FNAME}) do |op, io| Token(TkUMINUS).set_text(op) end @OP.def_rules("+", "-") do |op, io| catch(:RET) do if @lex_state == EXPR_ARG if @space_seen and peek(0) =~ /[0-9]/ throw :RET, identify_number(op) else @lex_state = EXPR_BEG end elsif @lex_state != EXPR_END and peek(0) =~ /[0-9]/ throw :RET, identify_number(op) else @lex_state = EXPR_BEG end Token(op).set_text(op) end end @OP.def_rule(".") do @lex_state = EXPR_BEG if peek(0) =~ /[0-9]/ ungetc identify_number("") else # for obj.if @lex_state = EXPR_DOT Token(TkDOT).set_text(".") end end @OP.def_rules("..", "...") do |op, io| @lex_state = EXPR_BEG Token(op).set_text(op) end lex_int2 end def lex_int2 @OP.def_rules("]", "}", ")") do |op, io| @lex_state = EXPR_END @indent -= 1 Token(op).set_text(op) end @OP.def_rule(":") do if (@colonblock_seen && @lex_state != EXPR_BEG) || peek(0) =~ /\s/ @lex_state = EXPR_BEG tk = Token(TkCOLON) else @lex_state = EXPR_FNAME tk = Token(TkSYMBEG) end tk.set_text(":") end @OP.def_rule("::") do # p @lex_state.id2name, @space_seen if @lex_state == EXPR_BEG or @lex_state == EXPR_ARG && @space_seen @lex_state = EXPR_BEG tk = Token(TkCOLON3) else @lex_state = EXPR_DOT tk = Token(TkCOLON2) end tk.set_text("::") end @OP.def_rule("/") do |op, io| if @lex_state == EXPR_BEG || @lex_state == EXPR_MID identify_string(op) elsif peek(0) == '=' getc @lex_state = EXPR_BEG Token(TkOPASGN, :/).set_text("/=") #") elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/ identify_string(op) else @lex_state = EXPR_BEG Token("/").set_text(op) end end @OP.def_rules("^") do @lex_state = EXPR_BEG Token("^").set_text("^") end # @OP.def_rules("^=") do # @lex_state = EXPR_BEG # Token(TkOPASGN, :^) # end @OP.def_rules(",", ";") do |op, io| @colonblock_seen = false @lex_state = EXPR_BEG Token(op).set_text(op) end @OP.def_rule("~") do @lex_state = EXPR_BEG Token("~").set_text("~") end @OP.def_rule("~@", proc{@lex_state = EXPR_FNAME}) do @lex_state = EXPR_BEG Token("~").set_text("~@") end @OP.def_rule("(") do @indent += 1 # if @lex_state == EXPR_BEG || @lex_state == EXPR_MID # @lex_state = EXPR_BEG # tk = Token(TkfLPAREN) # else @lex_state = EXPR_BEG tk = Token(TkLPAREN) # end tk.set_text("(") end @OP.def_rule("[]", proc{@lex_state == EXPR_FNAME}) do Token("[]").set_text("[]") end @OP.def_rule("[]=", proc{@lex_state == EXPR_FNAME}) do Token("[]=").set_text("[]=") end @OP.def_rule("[") do @indent += 1 # if @lex_state == EXPR_FNAME # t = Token(TkfLBRACK) # else # if @lex_state == EXPR_BEG || @lex_state == EXPR_MID # t = Token(TkLBRACK) # elsif @lex_state == EXPR_ARG && @space_seen # else # t = Token(TkfLBRACK) # end # end t = Token(TkLBRACK) @lex_state = EXPR_BEG t.set_text("[") end @OP.def_rule("{") do @indent += 1 # if @lex_state != EXPR_END && @lex_state != EXPR_ARG # t = Token(TkLBRACE) # else # t = Token(TkfLBRACE) # end t = Token(TkLBRACE) @lex_state = EXPR_BEG t.set_text("{") end @OP.def_rule('\\') do #' if getc == "\n" @space_seen = true @continue = true Token(TkSPACE).set_text("\\\n") else ungetc Token("\\").set_text("\\") #" end end @OP.def_rule('%') do |op, io| if @lex_state == EXPR_BEG || @lex_state == EXPR_MID identify_quotation('%') elsif peek(0) == '=' getc Token(TkOPASGN, "%").set_text("%=") elsif @lex_state == EXPR_ARG and @space_seen and peek(0) !~ /\s/ identify_quotation('%') else @lex_state = EXPR_BEG Token("%").set_text("%") end end @OP.def_rule('$') do #' identify_gvar end @OP.def_rule('@') do if peek(0) =~ /[@\w_]/ ungetc identify_identifier else Token("@").set_text("@") end end # @OP.def_rule("def", proc{|op, io| /\s/ =~ io.peek(0)}) do # |op, io| # @indent += 1 # @lex_state = EXPR_FNAME # # @lex_state = EXPR_END # # until @rests[0] == "\n" or @rests[0] == ";" # # rests.shift # # end # end @OP.def_rule("__END__", proc{@prev_char_no == 0 && peek(0) =~ /[\r\n]/}) do throw :eof end @OP.def_rule("") do |op, io| printf "MATCH: start %s: %s\n", op, io.inspect if RubyLex.debug? if peek(0) =~ /[0-9]/ t = identify_number("") elsif peek(0) =~ /[\w_]/ t = identify_identifier end printf "MATCH: end %s: %s\n", op, io.inspect if RubyLex.debug? t end p @OP if RubyLex.debug? end def identify_gvar @lex_state = EXPR_END str = "$" tk = case ch = getc when /[~_*$?!@\/\\;,=:<>".]/ #" str << ch Token(TkGVAR, str) when "-" str << "-" << getc Token(TkGVAR, str) when "&", "`", "'", "+" str << ch Token(TkBACK_REF, str) when /[1-9]/ str << ch while (ch = getc) =~ /[0-9]/ str << ch end ungetc Token(TkNTH_REF) when /\w/ ungetc ungetc return identify_identifier else ungetc Token("$") end tk.set_text(str) end def identify_identifier token = "" token.concat getc if peek(0) =~ /[$@]/ token.concat getc if peek(0) == "@" while (ch = getc) =~ /\w|_/ print ":", ch, ":" if RubyLex.debug? token.concat ch end ungetc if ch == "!" or ch == "?" token.concat getc end # fix token # $stderr.puts "identifier - #{token}, state = #@lex_state" case token when /^\$/ return Token(TkGVAR, token).set_text(token) when /^\@/ @lex_state = EXPR_END return Token(TkIVAR, token).set_text(token) end if @lex_state != EXPR_DOT print token, "\n" if RubyLex.debug? token_c, *trans = TkReading2Token[token] if token_c # reserved word? if (@lex_state != EXPR_BEG && @lex_state != EXPR_FNAME && trans[1]) # modifiers token_c = TkSymbol2Token[trans[1]] @lex_state = trans[0] else if @lex_state != EXPR_FNAME if ENINDENT_CLAUSE.include?(token) @indent += 1 if ACCEPTS_COLON.include?(token) @colonblock_seen = true else @colonblock_seen = false end elsif DEINDENT_CLAUSE.include?(token) @indent -= 1 @colonblock_seen = false end @lex_state = trans[0] else @lex_state = EXPR_END end end return Token(token_c, token).set_text(token) end end if @lex_state == EXPR_FNAME @lex_state = EXPR_END if peek(0) == '=' token.concat getc end elsif @lex_state == EXPR_BEG || @lex_state == EXPR_DOT @lex_state = EXPR_ARG else @lex_state = EXPR_END end if token[0, 1] =~ /[A-Z]/ return Token(TkCONSTANT, token).set_text(token) elsif token[token.size - 1, 1] =~ /[!?]/ return Token(TkFID, token).set_text(token) else return Token(TkIDENTIFIER, token).set_text(token) end end def identify_here_document ch = getc if ch == "-" ch = getc indent = true end if /['"`]/ =~ ch # ' lt = ch quoted = "" while (c = getc) && c != lt quoted.concat c end else lt = '"' quoted = ch.dup while (c = getc) && c =~ /\w/ quoted.concat c end ungetc end ltback, @ltype = @ltype, lt reserve = "" while ch = getc reserve << ch if ch == "\\" #" ch = getc reserve << ch elsif ch == "\n" break end end str = "" while (l = gets) l.chomp! l.strip! if indent break if l == quoted str << l.chomp << "\n" end @reader.divert_read_from(reserve) @ltype = ltback @lex_state = EXPR_END Token(Ltype2Token[lt], str).set_text(str.dump) end def identify_quotation(initial_char) ch = getc if lt = PERCENT_LTYPE[ch] initial_char += ch ch = getc elsif ch =~ /\W/ lt = "\"" else # RubyLex.fail SyntaxError, "unknown type of %string ('#{ch}')" end # if ch !~ /\W/ # ungetc # next # end # @ltype = lt @quoted = ch unless @quoted = PERCENT_PAREN[ch] identify_string(lt, @quoted, ch, initial_char) if lt end def identify_number(start) str = start.dup if start == "+" or start == "-" or start == "" start = getc str << start end @lex_state = EXPR_END if start == "0" if peek(0) == "x" ch = getc str << ch match = /[0-9a-f_]/ else match = /[0-7_]/ end while ch = getc if ch !~ match ungetc break else str << ch end end return Token(TkINTEGER).set_text(str) end type = TkINTEGER allow_point = TRUE allow_e = TRUE while ch = getc case ch when /[0-9_]/ str << ch when allow_point && "." type = TkFLOAT if peek(0) !~ /[0-9]/ ungetc break end str << ch allow_point = false when allow_e && "e", allow_e && "E" str << ch type = TkFLOAT if peek(0) =~ /[+-]/ str << getc end allow_e = false allow_point = false else ungetc break end end Token(type).set_text(str) end def identify_string(ltype, quoted = ltype, opener=nil, initial_char = nil) @ltype = ltype @quoted = quoted subtype = nil str = "" str << initial_char if initial_char str << (opener||quoted) nest = 0 begin while ch = getc str << ch if @quoted == ch if nest == 0 break else nest -= 1 end elsif opener == ch nest += 1 elsif @ltype != "'" && @ltype != "]" and ch == "#" ch = getc if ch == "{" subtype = true str << ch << skip_inner_expression else ungetc(ch) end elsif ch == '\\' #' str << read_escape end end if @ltype == "/" if peek(0) =~ /i|o|n|e|s/ str << getc end end if subtype Token(DLtype2Token[ltype], str) else Token(Ltype2Token[ltype], str) end.set_text(str) ensure @ltype = nil @quoted = nil @lex_state = EXPR_END end end def skip_inner_expression res = "" nest = 0 while (ch = getc) res << ch if ch == '}' break if nest.zero? nest -= 1 elsif ch == '{' nest += 1 end end res end def identify_comment @ltype = "#" comment = "#" while ch = getc if ch == "\\" ch = getc if ch == "\n" ch = " " else comment << "\\" end else if ch == "\n" @ltype = nil ungetc break end end comment << ch end return Token(TkCOMMENT).set_text(comment) end def read_escape res = "" case ch = getc when /[0-7]/ ungetc ch 3.times do case ch = getc when /[0-7]/ when nil break else ungetc break end res << ch end when "x" res << ch 2.times do case ch = getc when /[0-9a-fA-F]/ when nil break else ungetc break end res << ch end when "M" res << ch if (ch = getc) != '-' ungetc else res << ch if (ch = getc) == "\\" #" res << ch res << read_escape else res << ch end end when "C", "c" #, "^" res << ch if ch == "C" and (ch = getc) != "-" ungetc else res << ch if (ch = getc) == "\\" #" res << ch res << read_escape else res << ch end end else res << ch end res end end end end yard-0.8.7.3/lib/yard/parser/ruby/ast_node.rb0000644000004100000410000003645712261240652021000 0ustar www-datawww-datamodule YARD module Parser module Ruby # Builds and s-expression by creating {AstNode} objects with # the type provided by the first argument. # # @example An implicit list of keywords # ast = s(s(:kw, "if"), s(:kw, "else")) # ast.type # => :list # @example A method call # s(:command, s(:var_ref, "mymethod")) # # @overload s(*nodes, opts = {}) # @param [Array] nodes a list of nodes. # @param [Hash] opts any extra options (docstring, file, source) to # set on the object # @return [AstNode] an implicit node where node.type == +:list+ # @overload s(type, *children, opts = {}) # @param [Symbol] type the node type # @param [Array] children any child nodes inside this one # @param [Hash] opts any extra options to set on the object # @return [AstNode] a node of type +type+. # @see AstNode#initialize def s(*args) type = Symbol === args.first ? args.shift : :list opts = Hash === args.last ? args.pop : {} AstNode.node_class_for(type).new(type, args, opts) end # An AST node is characterized by a type and a list of children. It # is most easily represented by the s-expression {#s} such as: # # AST for "if true; 5 end": # s(s(:if, s(:var_ref, s(:kw, "true")), s(s(:int, "5")), nil)) # # The node type is not considered part of the list, only its children. # So +ast[0]+ does not refer to the type, but rather the first child # (or object). Items that are not +AstNode+ objects can be part of the # list, like Strings or Symbols representing names. To return only # the AstNode children of the node, use {#children}. class AstNode < Array attr_accessor :docstring_hash_flag attr_accessor :docstring, :docstring_range, :source # @deprecated Groups are now defined by directives # @see Tags::GroupDirective attr_accessor :group attr_writer :source_range, :line_range, :file, :full_source alias comments docstring alias comments_range docstring_range alias comments_hash_flag docstring_hash_flag alias to_s source # @return [Symbol] the node's unique symbolic type attr_accessor :type # @return [AstNode, nil] the node's parent or nil if it is a root node. attr_accessor :parent # @return [Range] the character range in {#full_source} represented # by the node def source_range reset_line_info unless @source_range @source_range end # @return [Range] the line range in {#full_source} represented # by the node def line_range reset_line_info unless @line_range @line_range end # @return [String] the filename the node was parsed from def file return parent.file if parent @file end # @return [String] the full source that the node was parsed from def full_source return parent.full_source if parent return @full_source if @full_source return IO.read(@file) if file && File.exist?(file) end # @return [String] the parse of {#full_source} that the node represents def source return parent.full_source[source_range] if parent full_source end # List of all known keywords # @return [Hash] KEYWORDS = { :class => true, :alias => true, :lambda => true, :do_block => true, :def => true, :defs => true, :begin => true, :rescue => true, :rescue_mod => true, :if => true, :if_mod => true, :else => true, :elsif => true, :case => true, :when => true, :next => true, :break => true, :retry => true, :redo => true, :return => true, :throw => true, :catch => true, :until => true, :until_mod => true, :while => true, :while_mod => true, :yield => true, :yield0 => true, :zsuper => true, :unless => true, :unless_mod => true, :for => true, :super => true, :return0 => true } # @group Creating an AstNode # Finds the node subclass that should be instantiated for a specific # node type # # @param [Symbol] type the node type to find a subclass for # @return [Class] a subclass of AstNode to instantiate the node with. def self.node_class_for(type) case type when :params ParameterNode when :call, :fcall, :vcall, :command, :command_call MethodCallNode when :if, :elsif, :if_mod, :unless, :unless_mod ConditionalNode when :for, :while, :while_mod, :until, :until_mod LoopNode when :def, :defs MethodDefinitionNode when :class, :sclass ClassNode when :module ModuleNode else if type.to_s =~ /_ref\Z/ ReferenceNode elsif type.to_s =~ /_literal\Z/ LiteralNode elsif KEYWORDS.has_key?(type) KeywordNode else AstNode end end end # Creates a new AST node # # @param [Symbol] type the type of node being created # @param [Array] arr the child nodes # @param [Hash] opts any extra line options # @option opts [Fixnum] :line (nil) the line the node starts on in source # @option opts [String] :char (nil) the character number the node starts on # in source # @option opts [Fixnum] :listline (nil) a special key like :line but for # list nodes # @option opts [Fixnum] :listchar (nil) a special key like :char but for # list nodes # @option opts [Boolean] :token (nil) whether the node represents a token def initialize(type, arr, opts = {}) super(arr) self.type = type self.line_range = opts[:line] self.source_range = opts[:char] @fallback_line = opts[:listline] @fallback_source = opts[:listchar] @token = true if opts[:token] end # @return [Boolean] whether the node is equal to another by checking # the list and type # @private def ==(ast) super && type == ast.type end # @group Traversing a Node # Searches through the node and all descendants and returns the # first node with a type matching any of +node_types+, otherwise # returns the original node (self). # # @example Returns the first method definition in a block of code # ast = YARD.parse_string("if true; def x; end end").ast # ast.jump(:def) # # => s(:def, s(:ident, "x"), s(:params, nil, nil, nil, nil, # # nil), s(s(:void_stmt, ))) # @example Returns first 'def' or 'class' statement # ast = YARD.parse_string("class X; def y; end end") # ast.jump(:def, :class).first # # => # @example If the node types are not present in the AST # ast = YARD.parse("def x; end") # ast.jump(:def) # # @param [Array] node_types a set of node types to match # @return [AstNode] the matching node, if one was found # @return [self] if no node was found def jump(*node_types) traverse {|child| return(child) if node_types.include?(child.type) } self end # @return [Array] the {AstNode} children inside the node def children @children ||= select {|e| AstNode === e } end # Traverses the object and yields each node (including descendants) in order. # # @yield each descendant node in order # @yieldparam [AstNode] self, or a child/descendant node # @return [void] def traverse nodes = [self] nodes.each.with_index do |node, index| yield node nodes.insert index+1, *node.children end end # @group Node Meta Types # @return [Boolean] whether the node is a token def token? @token end # @return [Boolean] whether the node is a reference (variable, # constant name) def ref? false end # @return [Boolean] whether the node is a literal value def literal? false end # @return [Boolean] whether the node is a keyword def kw? false end # @return [Boolean] whether the node is a method call def call? false end # @return [Boolean] whether the node is a method definition def def? false end # @return [Boolean] whether the node is a if/elsif/else condition def condition? false end # @return [Boolean] whether the node is a loop def loop? false end # @return [Boolean] whether the node has a block def block? respond_to?(:block) || condition? end # @group Getting Line Information # @return [Boolean] whether the node has a {#line_range} set def has_line? @line_range ? true : false end # @return [Fixnum] the starting line number of the node def line line_range && line_range.first end # @return [String] the first line of source represented by the node. def first_line full_source.split(/\r?\n/)[line - 1].strip end # @group Printing a Node # @return [String] the first line of source the node represents def show "\t#{line}: #{first_line}" end # @return [nil] pretty prints the node def pretty_print(q) objs = self.dup + [:__last__] objs.unshift(type) if type && type != :list options = [] if @docstring options << ['docstring', docstring] end if @source_range || @line_range options << ['line', line_range] options << ['source', source_range] end objs.pop if options.size == 0 q.group(3, 's(', ')') do q.seplist(objs, nil, :each) do |v| if v == :__last__ q.seplist(options, nil, :each) do |arr| k, v2 = *arr q.group(3) do q.text k q.group(3) do q.text ': ' q.pp v2 end end end else q.pp v end end end end # @return [String] inspects the object def inspect typeinfo = type && type != :list ? ':' + type.to_s + ', ' : '' 's(' + typeinfo + map(&:inspect).join(", ") + ')' end # @group Managing node state # Resets node state in tree def unfreeze @children = nil end # @endgroup private # Resets line information # @return [void] def reset_line_info if size == 0 self.line_range = @fallback_line self.source_range = @fallback_source elsif children.size > 0 f, l = children.first, children.last self.line_range = Range.new(f.line_range.first, l.line_range.last) self.source_range = Range.new(f.source_range.first, l.source_range.last) elsif @fallback_line || @fallback_source self.line_range = @fallback_line self.source_range = @fallback_source else self.line_range = 0...0 self.source_range = 0...0 end end end class ReferenceNode < AstNode def ref?; true end def path Array.new flatten end def namespace Array.new flatten[0...-1] end end class LiteralNode < AstNode def literal?; true end end class KeywordNode < AstNode def kw?; true end end class ParameterNode < AstNode def required_params; self[0] end def required_end_params; self[3] end def splat_param; self[2] ? self[2][0] : nil end def block_param; self[-1] ? self[-1][0] : nil end def optional_params optional = self[1] || [] if self[-3] && self[-3][0] && self[-3][0].type == :default_arg optional += self[-3] end optional.empty? ? nil : optional end def keyword_param; YARD.ruby2? ? self[-2] : nil end end class MethodCallNode < AstNode def call?; true end def namespace; first if index_adjust > 0 end def method_name(name_only = false) name = self[index_adjust] name_only ? name.jump(:ident).first.to_sym : name end def parameters(include_block_param = true) return [] if type == :vcall params = self[1 + index_adjust] return [] unless params params = call_has_paren? ? params.first : params return [] unless params include_block_param ? params : params[0...-1] end def block_param; parameters.last end def block last.type == :do_block || last.type == :brace_block ? last : nil end private def index_adjust [:call, :command_call].include?(type) ? 2 : 0 end def call_has_paren? [:fcall, :call].include?(type) end end class MethodDefinitionNode < AstNode def kw?; true end def def?; true end def namespace; first if index_adjust > 0 end def method_name(name_only = false) name = self[index_adjust] name_only ? name.jump(:ident).first.to_sym : name end def parameters(include_block_param = true) params = self[1 + index_adjust] params = params[0] if params.type == :paren include_block_param ? params : params[0...-1] end alias block last private def index_adjust type == :defs ? 2 : 0 end end class ConditionalNode < KeywordNode def condition?; true end def condition; first end def then_block; self[1] end def else_block if self[2] && !cmod? self[2].type == :elsif ? self[2] : self[2][0] end end private def cmod?; type =~ /_mod$/ end end class ClassNode < KeywordNode def class_name; first end def superclass; type == :sclass ? nil : self[1] end def block; last end end class ModuleNode < KeywordNode def module_name; first end def block; last end end class LoopNode < KeywordNode def loop?; true end def condition; type == :for ? s(self[0], self[1]) : first end def block; last end end # Represents a lone comment block in source class CommentNode < AstNode def docstring; first end def docstring=(value) end alias comments docstring def source; "" end def first_line; "" end end end end endyard-0.8.7.3/lib/yard/i18n/0000755000004100000410000000000012261240652015142 5ustar www-datawww-datayard-0.8.7.3/lib/yard/i18n/text.rb0000644000004100000410000001242712261240652016461 0ustar www-datawww-datamodule YARD module I18n # Provides some convenient features for translating a text. class Text # Creates a text object that has translation related features for # the input text. # # @param [#each_line] input a text to be translated. # @option options [Boolean] :have_header (false) whether the # input text has header or not. def initialize(input, options={}) @input = input @options = options end # Extracts translation target messages from +@input+. # # @yield [:attribute, name, value, line_no] the block that # recieves extracted an attribute in header. It may called many # times. # @yieldparam [String] name the name of extracted attribute. # @yieldparam [String] value the value of extracted attribute. # @yieldparam [Integer] line_no the defined line number of extracted # attribute. # @yield [:paragraph, text, start_line_no] the block that # recieves extracted a paragraph in body. Paragraph is a text # block separated by one or more empty lines. Empty line is a # line that contains only zero or more whitespaces. It may # called many times. # @yieldparam [String] text the text of extracted paragraph. # @yieldparam [Integer] start_line_no the start line number of # extracted paragraph. # @return [void] def extract_messages parse do |part| line_no = part[:line_no] case part[:type] when :markup, :empty_line # ignore when :attribute yield(:attribute, part[:name], part[:value], part[:line_no]) when :paragraph yield(:paragraph, part[:paragraph], part[:line_no]) end end end # Translates into +locale+. # # @param [Locale] locale the translation target locale. # @return [String] translated text. def translate(locale) translated_text = "" parse do |part| case part[:type] when :markup translated_text << part[:line] when :attribute prefix = "#{part[:prefix]}#{part[:name]}#{part[:infix]}" value = locale.translate(part[:value]) suffix = part[:suffix] translated_text << "#{prefix}#{value}#{suffix}" when :paragraph translated_text << locale.translate(part[:paragraph]) when :empty_line translated_text << part[:line] else raise "should not reach here: unexpected type: #{type}" end end translated_text end private def parse(&block) paragraph = "" paragraph_start_line = 0 line_no = 0 in_header = @options[:have_header] @input.each_line do |line| line_no += 1 if in_header case line when /^#!\S+\s*$/ if line_no == 1 emit_markup_event(line, line_no, &block) else in_header = false end when /^(\s*#\s*@)(\S+)(\s*)(.+?)(\s*)$/ emit_attribute_event(Regexp.last_match, line_no, &block) else in_header = false if line.strip.empty? emit_empty_line_event(line, line_no, &block) next end end next if in_header end case line when /^\s*$/ if paragraph.empty? emit_empty_line_event(line, line_no, &block) else paragraph << line emit_paragraph_event(paragraph, paragraph_start_line, line_no, &block) paragraph = "" end else paragraph_start_line = line_no if paragraph.empty? paragraph << line end end unless paragraph.empty? emit_paragraph_event(paragraph, paragraph_start_line, line_no, &block) end end def emit_markup_event(line, line_no) part = { :type => :markup, :line => line, :line_no => line_no, } yield(part) end def emit_attribute_event(match_data, line_no) part = { :type => :attribute, :prefix => match_data[1], :name => match_data[2], :infix => match_data[3], :value => match_data[4], :suffix => match_data[5], :line_no => line_no, } yield(part) end def emit_empty_line_event(line, line_no) part = { :type => :empty_line, :line => line, :line_no => line_no, } yield(part) end def emit_paragraph_event(paragraph, paragraph_start_line, line_no, &block) paragraph_part = { :type => :paragraph, :line_no => paragraph_start_line, } match_data = /(\s*)\z/.match(paragraph) if match_data paragraph_part[:paragraph] = match_data.pre_match yield(paragraph_part) emit_empty_line_event(match_data[1], line_no, &block) else paragraph_part[:paragraph] = paragraph yield(paragraph_part) end end end end end yard-0.8.7.3/lib/yard/i18n/message.rb0000644000004100000410000000322612261240652017116 0ustar www-datawww-datarequire "set" module YARD module I18n # +Message+ is a translation target message. It has message ID as # {#id} and some properties {#locations} and {#comments}. # # @since 0.8.1 class Message # @return [String] the message ID of the trnslation target message. attr_reader :id # @return [Set] the set of locations. Location is an array of # path and line number where the message is appeared. attr_reader :locations # @return [Set] the set of comments for the messages. attr_reader :comments # Creates a trasnlate target message for message ID +id+. # # @param [String] id the message ID of the translate target message. def initialize(id) @id = id @locations = Set.new @comments = Set.new end # Adds location information for the message. # # @param [String] path the path where the message appears. # @param [Integer] line the line number where the message appears. # @return [void] def add_location(path, line) @locations << [path, line] end # Adds a comment for the message. # # @param [String] comment the comment for the message to be added. # @return [void] def add_comment(comment) @comments << comment unless comment.nil? end # @param [Message] other the +Message+ to be compared. # @return [Boolean] checks whether this message is equal to another. def ==(other) other.is_a?(self.class) and @id == other.id and @locations == other.locations and @comments == other.comments end end end end yard-0.8.7.3/lib/yard/i18n/pot_generator.rb0000644000004100000410000002244512261240652020346 0ustar www-datawww-datarequire "stringio" module YARD module I18n # The +PotGenerator+ generates POT format string from # {CodeObjects::Base} and {CodeObjects::ExtraFileObject}. # # == POT and PO # # POT is an acronym for "Portable Object Template". POT is a # template file to create PO file. The extension for POT is # ".pot". PO file is an acronym for "Portable Object". PO file has # many parts of message ID (msgid) that is translation target # message and message string (msgstr) that is translated message # of message ID. If you want to tranlsate "Hello" in English into # "Bonjour" in French, "Hello" is the msgid ID and "Bonjour" is # msgstr. The extension for PO is ".po". # # == How to extract msgids # # The +PotGenerator+ has two parse methods: # # * {#parse_objects} for {CodeObjects::Base} # * {#parse_files} for {CodeObjects::ExtraFileObject} # # {#parse_objects} extracts msgids from docstring and tags of # {CodeObjects::Base} objects. The docstring of # {CodeObjects::Base} object is parsed and a paragraph is # extracted as a msgid. Tag name and tag text are extracted as # msgids from a tag. # # {#parse_files} extracts msgids from # {CodeObjects::ExtraFileObject} objects. The file content of # {CodeObjects::ExtraFileObject} object is parsed and a paragraph # is extracted as a msgid. # # == Usage # # To create a .pot file by +PotGenerator+, instantiate a # +PotGenerator+ with a relative working directory path from a # directory path that has created .pot file, parse # {CodeObjects::Base} objects and {CodeObjects::ExtraFileObject} # objects, generate a POT and write the generated POT to a .pot # file. The relative working directory path is ".." when the # working directory path is "." and the POT is wrote into # "po/yard.pot". # # @example Generate a .pot file # po_file_path = "po/yard.pot" # po_file_directory_pathname = Pathname.new(po_file_path).directory) # working_directory_pathname = Pathname.new(".") # relative_base_path = working_directory_pathname.relative_path_from(po_file_directory_pathname).to_s # # relative_base_path -> ".." # generator = YARD::I18n::PotGenerator.new(relative_base_path) # generator.parse_objects(objects) # generator.parse_files(files) # pot = generator.generate # po_file_directory_pathname.mkpath # File.open(po_file_path, "w") do |pot_file| # pot_file.print(pot) # end # @see http://www.gnu.org/software/gettext/manual/html_node/PO-Files.html # GNU gettext manual about details of PO file class PotGenerator # Extracted messages. # # @return [Messages] # @since 0.8.1 attr_reader :messages # Creates a POT generator that uses +relative_base_path+ to # generate locations for a msgid. +relative_base_path+ is # prepended to all locations. # # @param [String] relative_base_path a relative working # directory path from a directory path that has created .pot # file. def initialize(relative_base_path) @relative_base_path = relative_base_path @extracted_objects = {} @messages = Messages.new end # Parses {CodeObjects::Base} objects and stores extracted msgids # into {#messages} # # @param [Array] objects a list of # {CodeObjects::Base} to be parsed. # @return [void] def parse_objects(objects) objects.each do |object| extract_documents(object) end end # Parses {CodeObjects::ExtraFileObject} objects and stores # extracted msgids into {#messages}. # # @param [Array] files a list # of {CodeObjects::ExtraFileObject} objects to be parsed. # @return [void] def parse_files(files) files.each do |file| extract_paragraphs(file) end end # Generates POT from +@messages+. # # One PO file entry is generated from a +Message+ in # +@messages+. # # Locations of the +Message+ are used to generate the reference # line that is started with "#: ". +relative_base_path+ passed # when the generater is created is prepended to each path in location. # # Comments of the +Message+ are used to generate the # translater-comment line that is started with "# ". # # @return [String] POT format string def generate pot = header sorted_messages = @messages.sort_by do |message| sorted_locations = message.locations.sort_by do |location| location end sorted_locations.first || [] end sorted_messages.each do |message| generate_message(pot, message) end pot end private def header <<-'EOH' # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2011-11-20 22:17+0900\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" EOH end def generate_message(pot, message) message.comments.sort.each do |comment| pot << "# #{comment}\n" unless comment.empty? end message.locations.sort.each do |path, line| pot << "#: #{@relative_base_path}/#{path}:#{line}\n" end escaped_message_id = escape_message_id(message.id) escaped_message_id = escaped_message_id.gsub(/\n/, "\\\\n\"\n\"") pot << "msgid \"#{escaped_message_id}\"\n" pot << "msgstr \"\"\n" pot << "\n" pot end def escape_message_id(message_id) message_id.gsub(/(\\|")/) do special_character = $1 "\\#{special_character}" end end def register_message(id) @messages.register(id) end def extract_documents(object) return if @extracted_objects.has_key?(object) @extracted_objects[object] = true case object when CodeObjects::NamespaceObject object.children.each do |child| extract_documents(child) end end if object.group message = register_message(object.group) object.files.each do |path, line| message.add_location(path, line) end message.add_comment(object.path) unless object.path.empty? end docstring = object.docstring unless docstring.empty? text = Text.new(StringIO.new(docstring)) text.extract_messages do |type, *args| case type when :paragraph paragraph, line_no = *args message = register_message(paragraph.rstrip) object.files.each do |path, line| message.add_location(path, (docstring.line || line) + line_no) end message.add_comment(object.path) unless object.path.empty? else raise "should not reach here: unexpected type: #{type}" end end end docstring.tags.each do |tag| extract_tag_documents(tag) end end def extract_tag_documents(tag) extract_tag_name(tag) extract_tag_text(tag) end def extract_tag_name(tag) return if tag.name.nil? return if tag.name.is_a?(String) and tag.name.empty? key = "tag|#{tag.tag_name}|#{tag.name}" message = register_message(key) tag.object.files.each do |path, line| message.add_location(path, line) end tag_label = "@#{tag.tag_name}" tag_label << " [#{tag.types.join(', ')}]" if tag.types message.add_comment(tag_label) end def extract_tag_text(tag) return if tag.text.nil? return if tag.text.empty? message = register_message(tag.text) tag.object.files.each do |path, line| message.add_location(path, line) end tag_label = "@#{tag.tag_name}" tag_label << " [#{tag.types.join(', ')}]" if tag.types tag_label << " #{tag.name}" if tag.name message.add_comment(tag_label) end def extract_paragraphs(file) File.open(file.filename) do |input| text = Text.new(input, :have_header => true) text.extract_messages do |type, *args| case type when :attribute name, value, line_no = *args message = register_message(value) message.add_location(file.filename, line_no) message.add_comment(name) when :paragraph paragraph, line_no = *args message = register_message(paragraph.rstrip) message.add_location(file.filename, line_no) else raise "should not reach here: unexpected type: #{type}" end end end end end end end yard-0.8.7.3/lib/yard/i18n/messages.rb0000644000004100000410000000301212261240652017272 0ustar www-datawww-datamodule YARD module I18n # Acts as a container for {Message} objects. # # @since 0.8.1 class Messages include Enumerable # Creates a new container. def initialize @messages = {} end # Enumerates each {Message} in the container. # # @yieldparam [Message] message the next message object in # the enumeration. # @return [void] def each(&block) @messages.each_value(&block) end # @param [String] id the message ID to perform a lookup on. # @return [Message, nil] a registered message for the given +id+, # or nil if no message for the ID is found. def [](id) @messages[id] end # Registers a {Message}, the mssage ID of which is +id+. If # corresponding +Message+ is already registered, the previously # registered object is returned. # # @param [String] id the ID of the message to be registered. # @return [Message] the registered +Message+. def register(id) @messages[id] ||= Message.new(id) end # Checks if this messages list is equal to another messages list. # # @param [Messages] other the container to compare. # @return [Boolean] whether +self+ and +other+ is equivalence or not. def ==(other) other.is_a?(self.class) and @messages == other.messages end protected # @return [Hash{String=>Message}] the set of message objects attr_reader :messages end end end yard-0.8.7.3/lib/yard/i18n/locale.rb0000644000004100000410000000342212261240652016727 0ustar www-datawww-datamodule YARD module I18n # +Locale+ is a unit of translation. It has {#name} and a set of # messages. # # @since 0.8.2 class Locale class << self # @return [String, nil] the default locale name. # @since 0.8.4 attr_accessor :default undef default def default @@default ||= nil end undef default= def default=(locale) @@default = locale end end # @return [String] the name of the locale. It used IETF language # tag format +[language[_territory][.codeset][@modifier]]+. # @see http://tools.ietf.org/rfc/bcp/bcp47.txt # BCP 47 - Tags for Identifying Languages attr_reader :name # Creates a locale for +name+ locale. # # @param [String] name the locale name. def initialize(name) @name = name @messages = {} end # Loads translation messages from +locale_directory+/{#name}.po. # # @param [String] locale_directory the directory path that has # {#name}.po. # @return [Boolean] +true+ if PO file exists, +false+ otherwise. def load(locale_directory) return false if @name.nil? po_file = File.join(locale_directory, "#{@name}.po") return false unless File.exist?(po_file) require "yard/i18n/po_parser" return false unless POParser.available? po_parser = POParser.new @messages.merge!(po_parser.parse(po_file)) true end # @param [String] message the translation target message. # @return [String] translated message. If tarnslation isn't # registered, the +message+ is returned. def translate(message) @messages[message] || message end end end end yard-0.8.7.3/lib/yard/i18n/po_parser.rb0000644000004100000410000000314412261240652017463 0ustar www-datawww-datamodule YARD module I18n # +Locale+ is a wrapper for gettext's PO parsing feature. It hides # gettext API difference from YARD. # # @since 0.8.8 class POParser if RUBY_VERSION < "1.9" begin require "gettext/tools/poparser" require "gettext/runtime/mofile" @@gettext_version = 2 rescue LoadError log.warn "Need gettext gem 2.x for i18n feature:" log.warn " gem install gettext -v 2.3.9" end else begin require "gettext/po_parser" require "gettext/mo" @@gettext_version = 3 rescue LoadError begin require "gettext/tools/poparser" require "gettext/runtime/mofile" @@gettext_version = 2 rescue LoadError log.warn "Need gettext gem for i18n feature:" log.warn " gem install gettext" end end end class << self # @return [Boolean] true if gettext is available, false otherwise. def available? !@@gettext_version.nil? end end # Parses PO file. # # @param [String] file path of PO file to be parsed. # @return [Hash] parsed messages. def parse(file) case @@gettext_version when 2 parser = GetText::PoParser.new data = GetText::MoFile.new when 3 parser = GetText::POParser.new data = GetText::MO.new end parser.report_warning = false parser.parse_file(file, data) data end end end end yard-0.8.7.3/lib/yard/logging.rb0000644000004100000410000001342712261240652016345 0ustar www-datawww-datarequire 'logger' require 'thread' module YARD # Handles console logging for info, warnings and errors. # Uses the stdlib Logger class in Ruby for all the backend logic. class Logger < ::Logger # The list of characters displayed beside the progress bar to indicate # "movement". # @since 0.8.2 PROGRESS_INDICATORS = ["\u230C", "\u230D", "\u230E", "\u230F"] # @return [IO] the IO object being logged to # @since 0.8.2 def io; @logdev end def io=(pipe) @logdev = pipe end # @return [Boolean] whether backtraces should be shown (by default # this is on). def show_backtraces; @show_backtraces || level == DEBUG end attr_writer :show_backtraces # @return [Boolean] whether progress indicators should be shown when # logging CLIs (by default this is off). def show_progress return false if YARD.ruby18? # threading is too ineffective for progress support return false if YARD.windows? # windows has poor ANSI support return false unless io.tty? # no TTY support on IO return false if level > WARN # no progress in verbose/debug modes @show_progress end attr_writer :show_progress # The logger instance # @return [Logger] the logger instance def self.instance(pipe = STDOUT) @logger ||= new(pipe) end # Creates a new logger def initialize(pipe, *args) super(pipe, *args) self.io = pipe self.show_backtraces = true self.show_progress = false self.level = WARN self.formatter = method(:format_log) @progress_indicator = 0 @mutex = Mutex.new end # Changes the debug level to DEBUG if $DEBUG is set # and writes a debugging message. def debug(*args) self.level = DEBUG if $DEBUG super end # Captures the duration of a block of code for benchmark analysis. Also # calls {#progress} on the message to display it to the user. # # @todo Implement capture storage for reporting of benchmarks # @param [String] msg the message to display # @param [Symbol, nil] nontty_log the level to log as if the output # stream is not a TTY. Use +nil+ for no alternate logging. # @yield a block of arbitrary code to benchmark # @return [void] def capture(msg, nontty_log = :debug, &block) progress(msg, nontty_log) yield ensure clear_progress end # Displays a progress indicator for a given message. This progress report # is only displayed on TTY displays, otherwise the message is passed to # the +nontty_log+ level. # # @param [String] msg the message to log # @param [Symbol, nil] nontty_log the level to log as if the output # stream is not a TTY. Use +nil+ for no alternate logging. # @return [void] # @since 0.8.2 def progress(msg, nontty_log = :debug) send(nontty_log, msg) if nontty_log return unless show_progress icon = "" if defined?(::Encoding) icon = PROGRESS_INDICATORS[@progress_indicator] + " " end print("\e[2K\e[?25l\e[1m#{icon}#{msg}\e[0m\r") @mutex.synchronize do @progress_msg = msg @progress_indicator += 1 @progress_indicator %= PROGRESS_INDICATORS.size end Thread.new do sleep(0.05) @mutex.synchronize do progress(msg + ".", nil) if @progress_msg == msg end end end # Clears the progress indicator in the TTY display. # @return [void] # @since 0.8.2 def clear_progress return unless show_progress print_no_newline("\e[?25h\e[2K") @progress_msg = nil end # Displays an unformatted line to the logger output stream, adding # a newline. # @param [String] msg the message to display # @return [void] # @since 0.8.2 def puts(msg = '') print("#{msg}\n") end alias_method :print_no_newline, :<< private :print_no_newline # Displays an unformatted line to the logger output stream. # @param [String] msg the message to display # @return [void] # @since 0.8.2 def print(msg = '') clear_line print_no_newline(msg) end alias_method :<<, :print # Prints the backtrace +exc+ to the logger as error data. # # @param [Array] exc the backtrace list # @param [Symbol] level_meth the level to log backtrace at # @return [void] def backtrace(exc, level_meth = :error) return unless show_backtraces send(level_meth, "#{exc.class.class_name}: #{exc.message}") send(level_meth, "Stack trace:" + exc.backtrace[0..5].map {|x| "\n\t#{x}" }.join + "\n") end # Warns that the Ruby environment does not support continuations. Applies # to JRuby, Rubinius and MacRuby. This warning will only display once # per Ruby process. # # @deprecated Continuations are no longer needed by YARD 0.8.0+. # @return [void] def warn_no_continuations end # Sets the logger level for the duration of the block # # @example # log.enter_level(Logger::ERROR) do # YARD.parse_string "def x; end" # end # @param [Fixnum] new_level the logger level for the duration of the block. # values can be found in Ruby's Logger class. # @yield the block with the logger temporarily set to +new_level+ def enter_level(new_level = level, &block) old_level, self.level = level, new_level yield self.level = old_level end private # Override this internal Logger method to clear line def add(*args) clear_line super(*args) end def clear_line return unless @progress_msg print_no_newline("\e[2K\r") end # Log format (from Logger implementation). Used by Logger internally def format_log(sev, time, prog, msg) "[#{sev.downcase}]: #{msg}\n" end end end yard-0.8.7.3/lib/yard/version.rb0000644000004100000410000000004612261240652016375 0ustar www-datawww-datamodule YARD VERSION = "0.8.7.3" end yard-0.8.7.3/lib/yard/serializers/0000755000004100000410000000000012261240652016717 5ustar www-datawww-datayard-0.8.7.3/lib/yard/serializers/process_serializer.rb0000644000004100000410000000126312261240652023155 0ustar www-datawww-datamodule YARD module Serializers # Serializes an object to a process (like less) # # @example Serializing to a pager (less) # serializer = ProcessSerializer.new('less') # serializer.serialize(object, "data!") class ProcessSerializer < Base # Creates a new ProcessSerializer for the shell command +cmd+ # # @param [String] cmd the command that will accept data on stdin def initialize(cmd) @cmd = cmd end # Overrides serialize behaviour and writes data to standard input # of the associated command def serialize(object, data) IO.popen(@cmd, 'w') {|io| io.write(data) } end end end end yard-0.8.7.3/lib/yard/serializers/yardoc_serializer.rb0000644000004100000410000000673012261240652022764 0ustar www-datawww-datamodule YARD # Stubs marshal dumps and acts a delegate class for an object by path # # @private class StubProxy instance_methods.each {|m| undef_method(m) unless m.to_s =~ /^__|^object_id$/ } def _dump(depth) @path end def self._load(str) new(str) end def hash; @path.hash end def initialize(path, transient = false) @path = path @transient = transient end def method_missing(meth, *args, &block) return true if meth == :respond_to? && args.first == :_dump @object = nil if @transient @object ||= Registry.at(@path) @object.send(meth, *args, &block) rescue NoMethodError => e e.backtrace.delete_if {|l| l[0, __FILE__.size] == __FILE__ } raise end end module Serializers class YardocSerializer < FileSystemSerializer def initialize(yfile) super(:basepath => yfile, :extension => 'dat') end def objects_path; File.join(basepath, 'objects') end # @deprecated The registry no longer tracks proxy types def proxy_types_path; File.join(basepath, 'proxy_types') end def checksums_path; File.join(basepath, 'checksums') end def object_types_path; File.join(basepath, 'object_types') end def serialized_path(object) path = case object when String, Symbol object = object.to_s if object =~ /#/ object += '_i' elsif object =~ /\./ object += '_c' end object.split(/::|\.|#/).map do |p| p.gsub(/[^\w\.-]/) do |x| encoded = '_' x.each_byte { |b| encoded << ("%X" % b) } encoded end end.join('/') + '.' + extension when YARD::CodeObjects::RootObject 'root.dat' else super(object) end File.join('objects', path) end def serialize(object) if Hash === object super(object[:root], dump(object)) if object[:root] else super(object, dump(object)) end end def deserialize(path, is_path = false) path = File.join(basepath, serialized_path(path)) unless is_path if File.file?(path) log.debug "Deserializing #{path}..." Marshal.load(File.read_binary(path)) else log.debug "Could not find #{path}" nil end end private def dump(object) object = internal_dump(object, true) unless object.is_a?(Hash) Marshal.dump(object) end def internal_dump(object, first_object = false) if !first_object && object.is_a?(CodeObjects::Base) && !(Tags::OverloadTag === object) return StubProxy.new(object.path) end if object.is_a?(Hash) || object.is_a?(Array) || object.is_a?(CodeObjects::Base) || object.instance_variables.size > 0 object = object.dup end object.instance_variables.each do |ivar| ivar_obj = object.instance_variable_get(ivar) ivar_obj_dump = internal_dump(ivar_obj) object.instance_variable_set(ivar, ivar_obj_dump) end case object when Hash list = object.map do |k, v| [k, v].map {|item| internal_dump(item) } end object.replace(Hash[list]) when Array list = object.map {|item| internal_dump(item) } object.replace(list) end object end end end endyard-0.8.7.3/lib/yard/serializers/file_system_serializer.rb0000644000004100000410000000637412261240652024032 0ustar www-datawww-datamodule YARD module Serializers # Implements a serializer that reads from and writes to the filesystem. class FileSystemSerializer < Base # The base path to write data to. # @return [String] a base path attr_reader :basepath def basepath=(value) @basepath = options[:basepath] = value end # The extension of the filename (defaults to +html+) # # @return [String] the extension of the file. Empty string for no extension. attr_reader :extension def extension=(value) @extension = options[:extension] = value end # Creates a new FileSystemSerializer with options # # @option opts [String] :basepath ('doc') the base path to write data to # @option opts [String] :extension ('html') the extension of the serialized # path filename. If this is set to the empty string, no extension is used. def initialize(opts = {}) super @basepath = (options[:basepath] || 'doc').to_s @extension = (options.has_key?(:extension) ? options[:extension] : 'html').to_s end # Serializes object with data to its serialized path (prefixed by the +#basepath+). # # @return [String] the written data (for chaining) def serialize(object, data) path = File.join(basepath, serialized_path(object)) log.debug "Serializing to #{path}" File.open!(path, "wb") {|f| f.write data } end # Implements the serialized path of a code object. # # @param [CodeObjects::Base, CodeObjects::ExtraFileObject, String] object # the object to get a path for. The path of a string is the string itself. # @return [String] if object is a String, returns # object, otherwise the path on disk (without the basepath). def serialized_path(object) return object if object.is_a?(String) if object.is_a?(CodeObjects::ExtraFileObject) fspath = ['file.' + object.name + (extension.empty? ? '' : ".#{extension}")] else objname = object != YARD::Registry.root ? object.name.to_s : "top-level-namespace" objname += '_' + object.scope.to_s[0,1] if object.is_a?(CodeObjects::MethodObject) fspath = [objname + (extension.empty? ? '' : ".#{extension}")] if object.namespace && object.namespace.path != "" fspath.unshift(*object.namespace.path.split(CodeObjects::NSEP)) end end File.join(encode_path_components(*fspath)) end # Checks the disk for an object and returns whether it was serialized. # # @param [CodeObjects::Base] object the object to check # @return [Boolean] whether an object has been serialized to disk def exists?(object) File.exist?(File.join(basepath, serialized_path(object))) end private # Remove special chars from filenames. # Windows disallows \ / : * ? " < > | but we will just remove any # non alphanumeric (plus period, underscore and dash). def encode_path_components(*components) components.map! do |p| p.gsub(/[^\w\.-]/) do |x| encoded = '_' x.each_byte { |b| encoded << ("%X" % b) } encoded end end end end end end yard-0.8.7.3/lib/yard/serializers/base.rb0000644000004100000410000000602112261240652020155 0ustar www-datawww-datamodule YARD module Serializers # The abstract base serializer. Serializers allow templates to be # rendered to various endpoints. For instance, a {FileSystemSerializer} # would allow template contents to be written to the filesystem # # To implement a custom serializer, override the following methods: # * {#serialize} # * {#serialized_path} # # Optionally, a serializer can implement before and after filters: # * {#before_serialize} # * {#after_serialize} # # @abstract Override this class to implement a custom serializer. class Base # All serializer options are saved so they can be passed to other serializers. # # @return [SymbolHash] the serializer options attr_reader :options # @group Creating a New Serializer # Creates a new serializer with options # # @param [Hash] opts the options to assign to {#options} def initialize(opts = {}) @options = SymbolHash.new(false).update(opts) end # @group Serializing an Object # Serializes an object. # # @abstract This method should implement the logic that serializes # +data+ to the respective endpoint. This method should also call # the before and after callbacks {#before_serialize} and {#after_serialize} # @param [CodeObjects::Base, String] object the object to serialize the # data for. The object can also be a string (for non-object serialization) # @param [String] data the contents that should be serialized def serialize(object, data) end # The serialized path of an object # # @abstract This method should return the path of the object on the # endpoint. For instance, for a file serializer, this should return # the filename that represents the object on disk. # @param [CodeObjects::Base] object the object to return a path for # @return [String] the serialized path of an object def serialized_path(object) end # Returns whether an object has been serialized # # @abstract This method should return whether the endpoint already exists. # For instance, a file system serializer would check if the file exists # on disk. You will most likely use +#basepath+ and {#serialized_path} to # get the endpoint's location. # @param [CodeObjects::Base] object the object to check existence of # @return [Boolean] whether the endpoint exists. # @since 0.6.0 def exists?(object) false end # @group Callbacks # Called before serialization. # # @abstract Should run code before serialization. Should return false # if serialization should not occur. # @return [Boolean] whether or not serialization should occur def before_serialize; end # Called after serialization. # # @abstract Should run code after serialization. # @param [String] data the data that was serialized. # @return [void] def after_serialize(data); end end end endyard-0.8.7.3/lib/yard/serializers/stdout_serializer.rb0000644000004100000410000000174412261240652023025 0ustar www-datawww-datamodule YARD module Serializers # A serializer that writes data to standard output. class StdoutSerializer < Base # Creates a serializer to print text to stdout # # @param [Fixnum, nil] wrap if wrap is a number, wraps text to +wrap+ # columns, otherwise no wrapping is done. def initialize(wrap = nil) @wrap = wrap end # Overrides serialize behaviour to write data to standard output def serialize(object, data) print(@wrap ? word_wrap(data, @wrap) : data) end private # Wraps text to a specific column length # # @param [String] text the text to wrap # @param [Fixnum] length the column length to wrap to # @return [String] the wrapped text def word_wrap(text, length = 80) # See ruby-talk/10655 / Ernest Ellingson text.gsub(/\t/," ").gsub(/.{1,50}(?:\s|\Z)/){($& + 5.chr).gsub(/\n\005/,"\n").gsub(/\005/,"\n")} end end end endyard-0.8.7.3/lib/yard/globals.rb0000644000004100000410000000073112261240652016334 0ustar www-datawww-data# @group Global Convenience Methods # Shortcut for creating a YARD::CodeObjects::Proxy via a path # # @see YARD::CodeObjects::Proxy # @see YARD::Registry.resolve def P(namespace, name = nil, type = nil) namespace, name = nil, namespace if name.nil? YARD::Registry.resolve(namespace, name, false, true, type) end # The global {YARD::Logger} instance # # @return [YARD::Logger] the global {YARD::Logger} instance # @see YARD::Logger def log YARD::Logger.instance end yard-0.8.7.3/lib/yard/config.rb0000644000004100000410000002236612261240652016166 0ustar www-datawww-datamodule YARD # This class maintains all system-wide configuration for YARD and handles # the loading of plugins. To access options call {options}, and to load # a plugin use {load_plugin}. All other public methods are used by YARD # during load time. # # == User Configuration Files # # Persistent user configuration files can be stored in the file # +~/.yard/config+, which is read when YARD first loads. The file should # be formatted as YAML, and should contain a map of keys and values. # # Although you can specify any key-value mapping in the configuration file, # YARD defines special keys specified in {DEFAULT_CONFIG_OPTIONS}. # # An example of a configuration file is listed below: # # !!!yaml # load_plugins: true # Auto-load plugins when YARD starts # ignored_plugins: # - yard-broken # - broken2 # yard- prefix not necessary # autoload_plugins: # - yard-rspec # # == Automatic Loading of Plugins # # YARD 0.6.2 will no longer automatically load all plugins by default. This # option can be reset by setting 'load_plugins' to true in the configuration # file. In addition, you can specify a set of specific plugins to load on # load through the 'autoload_plugins' list setting. This setting is # independent of the 'load_plugins' value and will always be processed. # # == Ignored Plugins File # # YARD 0.5 and below used a +~/.yard/ignored_plugins+ file to specify # plugins to be ignored at load time. Ignored plugins in 0.6.2 and above # should now be specified in the main configuration file, though YARD # will support the +ignored_plugins+ file until 0.7.x. # # == Safe Mode # # YARD supports running in safe-mode. By doing this, it will avoid executing # any user code such as require files or queries. Plugins will still be # loaded with safe mode on, because plugins are properly namespaced with # a 'yard-' prefix, must be installed as a gem, and therefore cannot be # touched by the user. To specify safe mode, use the +safe_mode+ key. # # == Plugin Specific Configuration # # Additional settings can be defined within the configuration file # specifically to provide configuration for a plugin. A plugin that utilizes # the YARD configuration is strongly encouraged to utilize namespacing of # their configuration content. # # !!!yaml # load_plugins: true # Auto-load plugins when YARD starts # ignored_plugins: # - yard-broken # - broken2 # yard- prefix not necessary # autoload_plugins: # - yard-rspec # # Plugin Specific Configuration # yard-sample-plugin: # show-results-inline: true # # As the configuration is available system wide, it can be # accessed within the plugin code. # # # if YARD::Config.options['yard-sample-plugin'] and # YARD::Config.options['yard-sample-plugin']['show-results-inline'] # # ... perform the action that places the results inline ... # else # # ... do the default behavior of not showing the results inline ... # end # # When accessing the configuration, be aware that this file is user managed # so configuration keys and values may not be present. Make no assumptions and # instead ensure that you check for the existence of keys before proceeding to # retrieve values. # # @since 0.6.2 # @see options class Config class << self # The system-wide configuration options for YARD # @return [SymbolHash] a map a key-value pair settings. # @see DEFAULT_CONFIG_OPTIONS attr_accessor :options end # The location where YARD stores user-specific settings CONFIG_DIR = File.expand_path('~/.yard') # The main configuration YAML file. CONFIG_FILE = File.join(CONFIG_DIR, 'config') # File listing all ignored plugins # @deprecated Set `ignored_plugins` in the {CONFIG_FILE} instead. IGNORED_PLUGINS = File.join(CONFIG_DIR, 'ignored_plugins') # Default configuration options DEFAULT_CONFIG_OPTIONS = { :load_plugins => false, # Whether to load plugins automatically with YARD :ignored_plugins => [], # A list of ignored plugins by name :autoload_plugins => [], # A list of plugins to be automatically loaded :safe_mode => false # Does not execute or eval any user-level code } # The prefix used for YARD plugins. Name your gem with this prefix # to allow it to be used as a plugin. YARD_PLUGIN_PREFIX = /^yard[-_]/ # Loads settings from {CONFIG_FILE}. This method is called by YARD at # load time and should not be called by the user. # @return [void] def self.load self.options = SymbolHash.new(false) options.update(DEFAULT_CONFIG_OPTIONS) options.update(read_config_file) load_commandline_safemode add_ignored_plugins_file translate_plugin_names load_plugins rescue log.error "Invalid configuration file, using default options." options.update(DEFAULT_CONFIG_OPTIONS) end # Saves settings to {CONFIG_FILE}. # @return [void] def self.save require 'yaml' Dir.mkdir(CONFIG_DIR) unless File.directory?(CONFIG_DIR) File.open(CONFIG_FILE, 'w') {|f| f.write(YAML.dump(options)) } end # Loads gems that match the name 'yard-*' (recommended) or 'yard_*' except # those listed in +~/.yard/ignored_plugins+. This is called immediately # after YARD is loaded to allow plugin support. # # @return [Boolean] true if all plugins loaded successfully, false otherwise. def self.load_plugins load_gem_plugins && load_autoload_plugins && load_commandline_plugins ? true : false end # Loads an individual plugin by name. It is not necessary to include the # +yard-+ plugin prefix here. # # @param [String] name the name of the plugin (with or without +yard-+ prefix) # @return [Boolean] whether the plugin was successfully loaded def self.load_plugin(name) name = translate_plugin_name(name) return false if options[:ignored_plugins].include?(name) return false if name =~ /^yard-doc-/ log.debug "Loading plugin '#{name}'..." require name true rescue LoadError => e load_plugin_failed(name, e) end private # Load gem plugins if :load_plugins is true def self.load_gem_plugins return true unless options[:load_plugins] require 'rubygems' result = true Gem.source_index.find_name('').each do |gem| begin next true unless gem.name =~ YARD_PLUGIN_PREFIX load_plugin(gem.name) rescue Gem::LoadError => e tmp = load_plugin_failed(gem.name, e) result = tmp if !tmp end end result rescue LoadError log.debug "RubyGems is not present, skipping plugin loading" false end # Load plugins set in :autoload_plugins def self.load_autoload_plugins options[:autoload_plugins].each {|name| load_plugin(name) } end # Load plugins from {#arguments} def self.load_commandline_plugins with_yardopts do arguments.each_with_index do |arg, i| next unless arg == '--plugin' load_plugin(arguments[i+1]) end end end # Check for command-line safe_mode switch in {#arguments} def self.load_commandline_safemode with_yardopts do arguments.each_with_index do |arg, i| options[:safe_mode] = true if arg == '--safe' end end end # Print a warning if the plugin failed to load # @return [false] def self.load_plugin_failed(name, exception) log.warn "Error loading plugin '#{name}'" log.backtrace(exception) if $DEBUG false end # Legacy support for {IGNORED_PLUGINS} def self.add_ignored_plugins_file if File.file?(IGNORED_PLUGINS) options[:ignored_plugins] += File.read(IGNORED_PLUGINS).split(/\s+/) end end # Translates plugin names to add yard- prefix. def self.translate_plugin_names options[:ignored_plugins].map! {|name| translate_plugin_name(name) } options[:autoload_plugins].map! {|name| translate_plugin_name(name) } end # Loads the YAML configuration file into memory # @return [Hash] the contents of the YAML file from disk # @see CONFIG_FILE def self.read_config_file if File.file?(CONFIG_FILE) require 'yaml' YAML.load_file(CONFIG_FILE) else {} end end # Sanitizes and normalizes a plugin name to include the 'yard-' prefix. # @param [String] name the plugin name # @return [String] the sanitized and normalized plugin name. def self.translate_plugin_name(name) name = name.gsub('/', '') # Security sanitization name = "yard-" + name unless name =~ YARD_PLUGIN_PREFIX name end # Temporarily loads .yardopts file into @yardopts def self.with_yardopts(&block) yfile = CLI::Yardoc::DEFAULT_YARDOPTS_FILE @yardopts = File.file?(yfile) ? File.read_binary(yfile).shell_split : [] result = yield @yardopts = nil result end # @return [Array] arguments from commandline and yardopts file def self.arguments ARGV + @yardopts end end Config.options = Config::DEFAULT_CONFIG_OPTIONS end yard-0.8.7.3/lib/yard/code_objects/0000755000004100000410000000000012261240652017006 5ustar www-datawww-datayard-0.8.7.3/lib/yard/code_objects/constant_object.rb0000644000004100000410000000062512261240652022515 0ustar www-datawww-datamodule YARD::CodeObjects # A +ConstantObject+ represents a Ruby constant (not a module or class). # To access the constant's (source code) value, use {#value}. class ConstantObject < Base # The source code representing the constant's value # @return [String] the value the constant is set to attr_reader :value def value=(value) @value = format_source(value) end end endyard-0.8.7.3/lib/yard/code_objects/root_object.rb0000644000004100000410000000075012261240652021646 0ustar www-datawww-datamodule YARD module CodeObjects # Represents the root namespace object (the invisible Ruby module that # holds all top level modules, class and other objects). class RootObject < ModuleObject def path; @path ||= "" end def inspect; @inspect ||= "#" end def root?; true end def title; 'Top Level Namespace' end def equal?(other) other == :root ? true : super(other) end def hash; :root.hash end end end endyard-0.8.7.3/lib/yard/code_objects/class_object.rb0000644000004100000410000001173312261240652021773 0ustar www-datawww-datamodule YARD::CodeObjects # A ClassObject represents a Ruby class in source code. It is a {ModuleObject} # with extra inheritance semantics through the superclass. class ClassObject < NamespaceObject # The {ClassObject} that this class object inherits from in Ruby source. # @return [ClassObject] a class object that is the superclass of this one attr_reader :superclass # Creates a new class object in +namespace+ with +name+ # # @see Base.new def initialize(namespace, name, *args, &block) super if is_exception? self.superclass ||= "::Exception" unless P(namespace, name) == P(:Exception) else case P(namespace, name).path when "BasicObject" nil when "Object" self.superclass ||= "::BasicObject" else self.superclass ||= "::Object" end end end # Whether or not the class is a Ruby Exception # # @return [Boolean] whether the object represents a Ruby exception def is_exception? inheritance_tree.reverse.any? {|o| BUILTIN_EXCEPTIONS_HASH.has_key? o.path } end # Returns the inheritance tree of the object including self. # # @param [Boolean] include_mods whether or not to include mixins in the # inheritance tree. # @return [Array] the list of code objects that make up # the inheritance tree. def inheritance_tree(include_mods = false) list = (include_mods ? mixins(:instance, :class) : []) if superclass.is_a?(Proxy) || superclass.respond_to?(:inheritance_tree) list += [superclass] unless superclass == P(:Object) || superclass == P(:BasicObject) end [self] + list.map do |m| next m if m == self next m unless m.respond_to?(:inheritance_tree) m.inheritance_tree(include_mods) end.flatten.uniq end # Returns the list of methods matching the options hash. Returns # all methods if hash is empty. # # @param [Hash] opts the options hash to match # @option opts [Boolean] :inherited (true) whether inherited methods should be # included in the list # @option opts [Boolean] :included (true) whether mixed in methods should be # included in the list # @return [Array] the list of methods that matched def meths(opts = {}) opts = SymbolHash[:inherited => true].update(opts) list = super(opts) list += inherited_meths(opts).reject do |o| next(false) if opts[:all] list.find {|o2| o2.name == o.name && o2.scope == o.scope } end if opts[:inherited] list end # Returns only the methods that were inherited. # # @return [Array] the list of inherited method objects def inherited_meths(opts = {}) inheritance_tree[1..-1].inject([]) do |list, superclass| if superclass.is_a?(Proxy) list else list += superclass.meths(opts).reject do |o| next(false) if opts[:all] child(:name => o.name, :scope => o.scope) || list.find {|o2| o2.name == o.name && o2.scope == o.scope } end end end end # Returns the list of constants matching the options hash. # # @param [Hash] opts the options hash to match # @option opts [Boolean] :inherited (true) whether inherited constant should be # included in the list # @option opts [Boolean] :included (true) whether mixed in constant should be # included in the list # @return [Array] the list of constant that matched def constants(opts = {}) opts = SymbolHash[:inherited => true].update(opts) super(opts) + (opts[:inherited] ? inherited_constants : []) end # Returns only the constants that were inherited. # # @return [Array] the list of inherited constant objects def inherited_constants inheritance_tree[1..-1].inject([]) do |list, superclass| if superclass.is_a?(Proxy) list else list += superclass.constants.reject do |o| child(:name => o.name) || list.find {|o2| o2.name == o.name } end end end end # Sets the superclass of the object # # @param [Base, Proxy, String, Symbol, nil] object the superclass value # @return [void] def superclass=(object) case object when Base, Proxy, NilClass @superclass = object when String, Symbol @superclass = Proxy.new(namespace, object) else raise ArgumentError, "superclass must be CodeObject, Proxy, String or Symbol" end if name == @superclass.name && namespace != YARD::Registry.root && !object.is_a?(Base) @superclass = Proxy.new(namespace.namespace, object) end if @superclass == self msg = "superclass #{@superclass.inspect} cannot be the same as the declared class #{self.inspect}" @superclass = P("::Object") raise ArgumentError, msg end end end end yard-0.8.7.3/lib/yard/code_objects/macro_object.rb0000644000004100000410000001631712261240652021772 0ustar www-datawww-datarequire 'ostruct' module YARD module CodeObjects # A MacroObject represents a docstring defined through +@!macro NAME+ and can be # reused by specifying the tag +@!macro NAME+. You can also provide the # +attached+ type flag to the macro definition to have it attached to the # specific DSL method so it will be implicitly reused. # # Macros are fully described in the {file:docs/Tags.md#macro Tags Overview} # document. # # @example Creating a basic named macro # # @!macro prop # # @!method $1(${3-}) # # @return [$2] the value of the $0 # property :foo, String, :a, :b # # # @!macro prop # property :bar, Numeric, :value # # @example Creating a macro that is attached to the method call # # @!macro [attach] prop2 # # @!method $1(value) # property :foo # # # Extra data added to docstring # property :bar class MacroObject < Base MACRO_MATCH = /(\\)?\$(?:\{(-?\d+|\*)(-)?(-?\d+)?\}|(-?\d+|\*))/ class << self # Creates a new macro and fills in the relevant properties. # @param [String] macro_name the name of the macro, must be unique. # @param [String] data the data the macro should expand when re-used # @param [CodeObjects::Base] method_object an object to attach this # macro to. If supplied, {#attached?} will be true # @return [MacroObject] the newly created object def create(macro_name, data, method_object = nil) obj = new(:root, macro_name) obj.macro_data = data obj.method_object = method_object obj end # Finds a macro using +macro_name+ # @param [#to_s] macro_name the name of the macro # @return [MacroObject] if a macro is found # @return [nil] if there is no registered macro by that name def find(macro_name) Registry.at('.macro.' + macro_name.to_s) end # Parses a given docstring and determines if the macro is "new" or # not. If the macro has $variable names or if it has a @!macro tag # with the [new] or [attached] flag, it is considered new. # # If a new macro is found, the macro is created and registered. Otherwise # the macro name is searched and returned. If a macro is not found, # nil is returned. # # @param [#to_s] macro_name the name of the macro # @param [CodeObjects::Base] method_object an optional method to attach # the macro to. Only used if the macro is being created, otherwise # this argument is ignored. # @return [MacroObject] the newly created or existing macro, depending # on whether the @!macro tag was a new tag or not. # @return [nil] if the +data+ has no macro tag or if the macro is # not new and no macro by the macro name is found. def find_or_create(macro_name, data, method_object = nil) if macro = find(name) macro else create(macro_name, data, method_object) end end alias create_docstring find_or_create # Expands +macro_data+ using the interpolation parameters. # # Interpolation rules: # * $0, $1, $2, ... = the Nth parameter in +call_params+ # * $* = the full statement source (excluding block) # * Also supports $!{N-M} ranges, as well as negative indexes on N or M # * Use \$ to escape the variable name in a macro. # # @!macro [new] macro.expand # @param [Array] call_params the method name and parameters # to the method call. These arguments will fill \$0-N # @param [String] full_source the full source line (excluding block) # interpolated as \$* # @param [String] block_source Currently unused. Will support # interpolating the block data as a variable. # @return [String] the expanded macro data # @param [String] macro_data the macro data to expand (taken from {#macro_data}) def expand(macro_data, call_params = [], full_source = '', block_source = '') macro_data = macro_data.all if macro_data.is_a?(Docstring) macro_data.gsub(MACRO_MATCH) do escape, first, last, rng = $1, $2 || $5, $4, $3 ? true : false next $&[1..-1] if escape if first == '*' last ? $& : full_source else first_i = first.to_i last_i = (last ? last.to_i : call_params.size) last_i = first_i unless rng params = call_params[first_i..last_i] params ? params.join(", ") : '' end end end # Applies a macro on a docstring by creating any macro data inside of # the docstring first. Equivalent to calling {find_or_create} and {apply_macro} # on the new macro object. # # @param [Docstring] docstring the docstring to create a macro out of # @!macro macro.expand # @see find_or_create def apply(docstring, call_params = [], full_source = '', block_source = '', method_object = nil) docstring = docstring.all if Docstring === docstring parser = Docstring.parser handler = OpenStruct.new handler.call_params = call_params[1..-1] handler.caller_method = call_params.first handler.statement = OpenStruct.new(:source => full_source) parser.parse(docstring, nil, handler).to_docstring.to_raw end # Applies a macro to a docstring, interpolating the macro's data on the # docstring and appending any extra local docstring data that was in # the original +docstring+ object. # # @param [MacroObject] macro the macro object # @!macro macro.expand def apply_macro(macro, docstring, call_params = [], full_source = '', block_source = '') apply(docstring, call_params, full_source, block_source) end end # @return [String] the macro data stored on the object attr_accessor :macro_data # @return [CodeObjects::Base] the method object that this macro is # attached to. attr_accessor :method_object # @return [Boolean] whether this macro is attached to a method def attached?; method_object ? true : false end # Overrides {Base#path} so the macro path is ".macro.MACRONAME" def path; '.macro.' + name.to_s end # Overrides the separator to be '.' def sep; '.' end # Expands the macro using # @param [Array] call_params a list of tokens that are passed # to the method call # @param [String] full_source the full method call (not including the block) # @param [String] block_source the source passed in the block of the method # call, if there is a block. # @example Expanding a Macro # macro.expand(%w(property foo bar), 'property :foo, :bar', '') #=> # "...macro data interpolating this line of code..." # @see expand def expand(call_params = [], full_source = '', block_source = '') self.class.expand(macro_data, call_params, full_source, block_source) end end end endyard-0.8.7.3/lib/yard/code_objects/proxy.rb0000644000004100000410000001717512261240652020527 0ustar www-datawww-datamodule YARD module CodeObjects # A special type of +NoMethodError+ when raised from a {Proxy} class ProxyMethodError < NoMethodError; end # The Proxy class is a way to lazily resolve code objects in # cases where the object may not yet exist. A proxy simply stores # an unresolved path until a method is called on the object, at which # point it does a lookup using {Registry.resolve}. If the object is # not found, a warning is raised and {ProxyMethodError} might be raised. # # @example Creates a Proxy to the String class from a module # # When the String class is parsed this method will # # begin to act like the String ClassObject. # Proxy.new(mymoduleobj, "String") # @see Registry.resolve # @see ProxyMethodError class Proxy def self.===(other) other.is_a?(self) end attr_reader :namespace alias_method :parent, :namespace # Creates a new Proxy # # @raise [ArgumentError] if namespace is not a NamespaceObject # @return [Proxy] self def initialize(namespace, name, type = nil) namespace = Registry.root if !namespace || namespace == :root if name =~ /^#{NSEPQ}/ namespace = Registry.root name = name[2..-1] end if name =~ /(?:#{NSEPQ}|#{ISEPQ}|#{CSEPQ})([^#{NSEPQ}#{ISEPQ}#{CSEPQ}]+)$/ @orignamespace, @origname = namespace, name @imethod = true if name.include? ISEP namespace = Proxy.new(namespace, $`) unless $`.empty? name = $1 else @orignamespace, @origname, @imethod = nil, nil, nil end @name = name.to_sym @namespace = namespace @obj = nil @imethod ||= nil self.type = type if @namespace.is_a?(ConstantObject) @origname = nil # forget these for a constant @orignamespace = nil @namespace = Proxy.new(@namespace.namespace, @namespace.value) end unless @namespace.is_a?(NamespaceObject) or @namespace.is_a?(Proxy) raise ArgumentError, "Invalid namespace object: #{namespace}" end # If the name begins with "::" (like "::String") # this is definitely a root level object, so # remove the namespace and attach it to the root if @name =~ /^#{NSEPQ}/ @name.gsub!(/^#{NSEPQ}/, '') @namespace = Registry.root end end # (see Base#name) def name(prefix = false) prefix ? (@imethod ? ISEP : '') + @name.to_s : @name end # Returns a text representation of the Proxy # @return [String] the object's #inspect method or P(OBJECTPATH) def inspect if obj = to_obj obj.inspect else "P(#{path})" end end # If the proxy resolves to an object, returns its path, otherwise # guesses at the correct path using the original namespace and name. # # @return [String] the assumed path of the proxy (or the real path # of the resolved object) def path if obj = to_obj obj.path else proxy_path end end alias to_s path alias to_str path alias title path # @return [Boolean] def is_a?(klass) if obj = to_obj obj.is_a?(klass) else self.class <= klass end end # @return [Boolean] def ===(other) if obj = to_obj obj === other else self.class <= other.class end end # @return [Boolean] def <=>(other) if other.respond_to? :path path <=> other.path else false end end # @return [Boolean] def equal?(other) if other.respond_to? :path path == other.path else false end end alias == equal? # @return [Integer] the object's hash value (for equality checking) def hash; path.hash end # Returns the class name of the object the proxy is mimicking, if # resolved. Otherwise returns +Proxy+. # @return [Class] the resolved object's class or +Proxy+ def class if obj = to_obj obj.class else Proxy end end # Returns the type of the proxy. If it cannot be resolved at the # time of the call, it will either return the inferred proxy type # (see {#type=}) or +:proxy+ # @return [Symbol] the Proxy's type # @see #type= def type if obj = to_obj obj.type else @type || :proxy end end # Allows a parser to infer the type of the proxy by its path. # @param [#to_sym] type the proxy's inferred type # @return [void] def type=(type) @type = type ? type.to_sym : nil end # @return [Boolean] def instance_of?(klass) self.class == klass end # @return [Boolean] def kind_of?(klass) self.class <= klass end # @return [Boolean] def respond_to?(meth, include_private = false) if obj = to_obj obj.respond_to?(meth, include_private) else super end end # Dispatches the method to the resolved object. # # @raise [ProxyMethodError] if the proxy cannot find the real object def method_missing(meth, *args, &block) if obj = to_obj obj.__send__(meth, *args, &block) else log.warn "Load Order / Name Resolution Problem on #{path}:" log.warn "-" log.warn "Something is trying to call #{meth} on object #{path} before it has been recognized." log.warn "This error usually means that you need to modify the order in which you parse files" log.warn "so that #{path} is parsed before methods or other objects attempt to access it." log.warn "-" log.warn "YARD will recover from this error and continue to parse but you *may* have problems" log.warn "with your generated documentation. You should probably fix this." log.warn "-" begin super rescue NoMethodError raise ProxyMethodError, "Proxy cannot call method ##{meth} on object '#{path}'" end end end # This class is never a root object def root?; false end private # @note this method fixes a bug in 1.9.2: http://gist.github.com/437136 def to_ary; nil end # Attempts to find the object that this unresolved object # references by checking if any objects by this name are # registered all the way up the namespace tree. # # @return [Base, nil] the registered code object or nil def to_obj return @obj if @obj if @obj = Registry.resolve(@namespace, (@imethod ? ISEP : '') + @name.to_s, false, false, @type) if @origname && @origname.include?("::") && !@obj.path.include?(@origname) # the object's path should include the original proxy namespace, # otherwise it's (probably) not the right object. @obj = nil else @namespace = @obj.namespace @name = @obj.name end end @obj end def proxy_path if @namespace.root? (@imethod ? ISEP : "") + name.to_s elsif @origname if @origname =~ /^[A-Z]/ @origname else [namespace.path, @origname].join end elsif name.to_s =~ /^[A-Z]/ # const name.to_s else # class meth? [namespace.path, name.to_s].join(CSEP) end end end end end yard-0.8.7.3/lib/yard/code_objects/module_object.rb0000644000004100000410000000117012261240652022145 0ustar www-datawww-datamodule YARD::CodeObjects # Represents a Ruby module. class ModuleObject < NamespaceObject # Returns the inheritance tree of mixins. # # @param [Boolean] include_mods if true, will include mixed in # modules (which is likely what is wanted). # @return [Array] a list of namespace objects def inheritance_tree(include_mods = false) return [self] unless include_mods [self] + mixins(:instance, :class).map do |m| next if m == self next m unless m.respond_to?(:inheritance_tree) m.inheritance_tree(true) end.compact.flatten.uniq end end end yard-0.8.7.3/lib/yard/code_objects/extended_method_object.rb0000644000004100000410000000140212261240652024016 0ustar www-datawww-datamodule YARD::CodeObjects # Represents an instance method of a module that was mixed into the class # scope of another namespace. # # @see MethodObject class ExtendedMethodObject instance_methods.each {|m| undef_method(m) unless m =~ /^__/ || m.to_sym == :object_id } # @return [Symbol] always +:class+ def scope; :class end # Sets up a delegate for {MethodObject} obj. # # @param [MethodObject] obj the instance method to treat as a mixed in # class method on another namespace. def initialize(obj) @del = obj end # Sends all methods to the {MethodObject} assigned in {#initialize} # @see #initialize # @see MethodObject def method_missing(sym, *args, &block) @del.__send__(sym, *args, &block) end end endyard-0.8.7.3/lib/yard/code_objects/extra_file_object.rb0000644000004100000410000000651412261240652023011 0ustar www-datawww-datamodule YARD::CodeObjects # An ExtraFileObject represents an extra documentation file (README or other # file). It is not strictly a CodeObject (does not inherit from `Base`) although # it implements `path`, `name` and `type`, and therefore should be structurally # compatible with most CodeObject interfaces. class ExtraFileObject attr_accessor :filename attr_writer :attributes attr_accessor :name # @since 0.8.3 attr_reader :locale # Creates a new extra file object. # @param [String] filename the location on disk of the file # @param [String] contents the file contents. If not set, the contents # will be read from disk using the +filename+. def initialize(filename, contents = nil) self.filename = filename self.name = File.basename(filename).gsub(/\.[^.]+$/, '') self.attributes = SymbolHash.new(false) @original_contents = contents @parsed = false @locale = nil ensure_parsed end alias path name def attributes ensure_parsed @attributes end def title attributes[:title] || name end def contents ensure_parsed @contents end def contents=(contents) @original_contents = contents @parsed = false end # @param [String] locale the locale name to be translated. # @return [void] # @since 0.8.3 def locale=(locale) @locale = locale @parsed = false end def inspect "#" end alias to_s inspect def type; :extra_file end def ==(other) return false unless self.class === other other.filename == filename end alias eql? == alias equal? == def hash; filename.hash end private def ensure_parsed return if @parsed @parsed = true @contents = parse_contents(@original_contents || File.read(@filename)) end # @param [String] data the file contents def parse_contents(data) retried = false cut_index = 0 data = translate(data) data = data.split("\n") data.each_with_index do |line, index| case line when /^#!(\S+)\s*$/ if index == 0 attributes[:markup] = $1 else cut_index = index break end when /^\s*#\s*@(\S+)\s*(.+?)\s*$/ attributes[$1] = $2 else cut_index = index break end end data = data[cut_index..-1] if cut_index > 0 contents = data.join("\n") if contents.respond_to?(:force_encoding) && attributes[:encoding] begin contents.force_encoding(attributes[:encoding]) rescue ArgumentError log.warn "Invalid encoding `#{attributes[:encoding]}' in #{filename}" end end contents rescue ArgumentError => e if retried && e.message =~ /invalid byte sequence/ # This should never happen. log.warn "Could not read #{filename}, #{e.message}. You probably want to set `--charset`." return '' end data.force_encoding('binary') if data.respond_to?(:force_encoding) retried = true retry end def translate(data) text = YARD::I18n::Text.new(data, :have_header => true) text.translate(YARD::Registry.locale(locale)) end end endyard-0.8.7.3/lib/yard/code_objects/class_variable_object.rb0000644000004100000410000000040212261240652023627 0ustar www-datawww-datamodule YARD::CodeObjects # Represents a class variable inside a namespace. The path is expressed # in the form "A::B::@@classvariable" class ClassVariableObject < Base # @return [String] the class variable's value attr_accessor :value end endyard-0.8.7.3/lib/yard/code_objects/method_object.rb0000644000004100000410000001353312261240652022146 0ustar www-datawww-datamodule YARD::CodeObjects # Represents a Ruby method in source class MethodObject < Base # The scope of the method (+:class+ or +:instance+) # # @return [Symbol] the scope attr_reader :scope # Whether the object is explicitly defined in source or whether it was # inferred by a handler. For instance, attribute methods are generally # inferred and therefore not explicitly defined in source. # # @return [Boolean] whether the object is explicitly defined in source. attr_accessor :explicit # Returns the list of parameters parsed out of the method signature # with their default values. # # @return [Array] a list of parameter names followed # by their default values (or nil) attr_accessor :parameters # Creates a new method object in +namespace+ with +name+ and an instance # or class +scope+ # # If scope is +:module+, this object is instantiated as a public # method in +:class+ scope, but also creates a new (empty) method # as a private +:instance+ method on the same class or module. # # @param [NamespaceObject] namespace the namespace # @param [String, Symbol] name the method name # @param [Symbol] scope +:instance+, +:class+, or +:module+ def initialize(namespace, name, scope = :instance, &block) @module_function = false @scope = nil # handle module function if scope == :module other = self.class.new(namespace, name, &block) other.visibility = :private scope = :class @module_function = true end @visibility = :public self.scope = scope self.parameters = [] super end # Changes the scope of an object from :instance or :class # @param [Symbol] v the new scope def scope=(v) reregister = @scope ? true : false # handle module function if v == :module other = self.class.new(namespace, name) other.visibility = :private @visibility = :public @module_function = true @path = nil end YARD::Registry.delete(self) @path = nil @scope = v.to_sym if @scope == :module @scope = :class end YARD::Registry.register(self) if reregister end # @return whether or not the method is the #initialize constructor method def constructor? name == :initialize && scope == :instance && namespace.is_a?(ClassObject) end # @return [Boolean] whether or not this method was created as a module # function # @since 0.8.0 def module_function? @module_function end # Returns the read/writer info for the attribute if it is one # @return [SymbolHash] if there is information about the attribute # @return [nil] if the method is not an attribute # @since 0.5.3 def attr_info return nil unless namespace.is_a?(NamespaceObject) namespace.attributes[scope][name.to_s.gsub(/=$/, '')] end # @return [Boolean] whether the method is a writer attribute # @since 0.5.3 def writer? !!((info = attr_info) && info[:write] == self) end # @return [Boolean] whether the method is a reader attribute # @since 0.5.3 def reader? !!((info = attr_info) && info[:read] == self) end # Tests if the object is defined as an attribute in the namespace # @return [Boolean] whether the object is an attribute def is_attribute? return false unless info = attr_info info[name.to_s =~ /=$/ ? :write : :read] ? true : false end # Tests if the object is defined as an alias of another method # @return [Boolean] whether the object is an alias def is_alias? return false unless namespace.is_a?(NamespaceObject) namespace.aliases.has_key? self end # Tests boolean {#explicit} value. # # @return [Boolean] whether the method is explicitly defined in source def is_explicit? explicit ? true : false end # @return [MethodObject] the object that this method overrides # @return [nil] if it does not override a method # @since 0.6.0 def overridden_method return nil if namespace.is_a?(Proxy) meths = namespace.meths(:all => true) meths.find {|m| m.path != path && m.name == name && m.scope == scope } end # Returns all alias names of the object # @return [Array] the alias names def aliases list = [] return list unless namespace.is_a?(NamespaceObject) namespace.aliases.each do |o, aname| list << o if aname == name && o.scope == scope end list end # Override path handling for instance methods in the root namespace # (they should still have a separator as a prefix). # @return [String] the path of a method def path @path ||= if !namespace || namespace.path == "" sep + super else super end end # Returns the name of the object. # # @example The name of an instance method (with prefix) # an_instance_method.name(true) # => "#mymethod" # @example The name of a class method (with prefix) # a_class_method.name(true) # => "mymethod" # @param [Boolean] prefix whether or not to show the prefix # @return [String] returns {#sep} + +name+ for an instance method if # prefix is true # @return [Symbol] the name without {#sep} if prefix is set to false def name(prefix = false) prefix ? (sep == ISEP ? "#{sep}#{super}" : super.to_s) : super end # Override separator to differentiate between class and instance # methods. # @return [String] "#" for an instance method, "." for class def sep if scope == :class namespace && namespace != YARD::Registry.root ? CSEP : NSEP else ISEP end end protected def copyable_attributes super - %w(scope module_function) end end end yard-0.8.7.3/lib/yard/code_objects/base.rb0000644000004100000410000005261012261240652020251 0ustar www-datawww-datamodule YARD module CodeObjects # A list of code objects. This array acts like a set (no unique items) # but also disallows any {Proxy} objects from being added. class CodeObjectList < Array # Creates a new object list associated with a namespace # # @param [NamespaceObject] owner the namespace the list should be associated with # @return [CodeObjectList] def initialize(owner = Registry.root) @owner = owner end # Adds a new value to the list # # @param [Base] value a code object to add # @return [CodeObjectList] self def push(value) value = Proxy.new(@owner, value) if value.is_a?(String) || value.is_a?(Symbol) if value.is_a?(CodeObjects::Base) || value.is_a?(Proxy) super(value) unless include?(value) else raise ArgumentError, "#{value.class} is not a valid CodeObject" end self end alias_method :<<, :push end # Namespace separator NSEP = '::' # Regex-quoted namespace separator NSEPQ = NSEP # Instance method separator ISEP = '#' # Regex-quoted instance method separator ISEPQ = ISEP # Class method separator CSEP = '.' # Regex-quoted class method separator CSEPQ = Regexp.quote CSEP # Regular expression to match constant name CONSTANTMATCH = /[A-Z]\w*/ # Regular expression to match namespaces (const A or complex path A::B) NAMESPACEMATCH = /(?:(?:#{NSEPQ}\s*)?#{CONSTANTMATCH})+/ # Regular expression to match a method name METHODNAMEMATCH = /[a-zA-Z_]\w*[!?=]?|[-+~]\@|<<|>>|=~|===?|<=>|[<>]=?|\*\*|[-\/+%^&*~`|]|\[\]=?/ # Regular expression to match a fully qualified method def (self.foo, Class.foo). METHODMATCH = /(?:(?:#{NAMESPACEMATCH}|[a-z]\w*)\s*(?:#{CSEPQ}|#{NSEPQ})\s*)?#{METHODNAMEMATCH}/ # All builtin Ruby exception classes for inheritance tree. BUILTIN_EXCEPTIONS = ["SecurityError", "Exception", "NoMethodError", "FloatDomainError", "IOError", "TypeError", "NotImplementedError", "SystemExit", "Interrupt", "SyntaxError", "RangeError", "NoMemoryError", "ArgumentError", "ThreadError", "EOFError", "RuntimeError", "ZeroDivisionError", "StandardError", "LoadError", "NameError", "LocalJumpError", "SystemCallError", "SignalException", "ScriptError", "SystemStackError", "RegexpError", "IndexError"] # All builtin Ruby classes for inheritance tree. # @note MatchingData is a 1.8.x legacy class BUILTIN_CLASSES = ["TrueClass", "Array", "Dir", "Struct", "UnboundMethod", "Object", "Fixnum", "Float", "ThreadGroup", "MatchingData", "MatchData", "Proc", "Binding", "Class", "Time", "Bignum", "NilClass", "Symbol", "Numeric", "String", "Data", "MatchData", "Regexp", "Integer", "File", "IO", "Range", "FalseClass", "Method", "Continuation", "Thread", "Hash", "Module"] + BUILTIN_EXCEPTIONS # All builtin Ruby modules for mixin handling. BUILTIN_MODULES = ["ObjectSpace", "Signal", "Marshal", "Kernel", "Process", "GC", "FileTest", "Enumerable", "Comparable", "Errno", "Precision", "Math"] # All builtin Ruby classes and modules. BUILTIN_ALL = BUILTIN_CLASSES + BUILTIN_MODULES # Hash of {BUILTIN_EXCEPTIONS} as keys and true as value (for O(1) lookups) BUILTIN_EXCEPTIONS_HASH = BUILTIN_EXCEPTIONS.inject({}) {|h,n| h.update(n => true) } # +Base+ is the superclass of all code objects recognized by YARD. A code # object is any entity in the Ruby language (class, method, module). A # DSL might subclass +Base+ to create a new custom object representing # a new entity type. # # == Registry Integration # Any created object associated with a namespace is immediately registered # with the registry. This allows the Registry to act as an identity map # to ensure that no object is represented by more than one Ruby object # in memory. A unique {#path} is essential for this identity map to work # correctly. # # == Custom Attributes # Code objects allow arbitrary custom attributes to be set using the # {#[]=} assignment method. # # == Namespaces # There is a special type of object called a "namespace". These are subclasses # of the {NamespaceObject} and represent Ruby entities that can have # objects defined within them. Classically these are modules and classes, # though a DSL might create a custom {NamespaceObject} to describe a # specific set of objects. # # @abstract This class should not be used directly. Instead, create a # subclass that implements {#path}, {#sep} or {#type}. # @see Registry # @see #path # @see #[]= # @see NamespaceObject class Base # The files the object was defined in. To add a file, use {#add_file}. # @return [Array] a list of files # @see #add_file attr_reader :files # The namespace the object is defined in. If the object is in the # top level namespace, this is {Registry.root} # @return [NamespaceObject] the namespace object attr_reader :namespace # The source code associated with the object # @return [String, nil] source, if present, or nil attr_reader :source # Language of the source code associated with the object. Defaults to # +:ruby+. # # @return [Symbol] the language type attr_accessor :source_type # The one line signature representing an object. For a method, this will # be of the form "def meth(arguments...)". This is usually the first # source line. # # @return [String] a line of source attr_accessor :signature # The non-localized documentation string associated with the object # @return [Docstring] the documentation string # @since 0.8.4 attr_reader :base_docstring undef base_docstring def base_docstring; @docstring end # Marks whether or not the method is conditionally defined at runtime # @return [Boolean] true if the method is conditionally defined at runtime attr_accessor :dynamic # @return [String] the group this object is associated with # @since 0.6.0 attr_accessor :group # Is the object defined conditionally at runtime? # @see #dynamic def dynamic?; @dynamic end # @return [Symbol] the visibility of an object (:public, :private, :protected) attr_accessor :visibility undef visibility= def visibility=(v) @visibility = v.to_sym end class << self # Allocates a new code object # @return [Base] # @see #initialize def new(namespace, name, *args, &block) raise ArgumentError, "invalid empty object name" if name.to_s.empty? if namespace.is_a?(ConstantObject) namespace = Proxy.new(namespace.namespace, namespace.value) end if name.to_s[0,2] == NSEP name = name.to_s[2..-1] namespace = Registry.root end if name =~ /(?:#{NSEPQ})([^:]+)$/ return new(Proxy.new(namespace, $`), $1, *args, &block) end obj = super(namespace, name, *args) existing_obj = Registry.at(obj.path) obj = existing_obj if existing_obj && existing_obj.class == self yield(obj) if block_given? obj end # Compares the class with subclasses # # @param [Object] other the other object to compare classes with # @return [Boolean] true if other is a subclass of self def ===(other) other.is_a?(self) end end # Creates a new code object # # @example Create a method in the root namespace # CodeObjects::Base.new(:root, '#method') # => # # @example Create class Z inside namespace X::Y # CodeObjects::Base.new(P("X::Y"), :Z) # or # CodeObjects::Base.new(Registry.root, "X::Y") # @param [NamespaceObject] namespace the namespace the object belongs in, # {Registry.root} or :root should be provided if it is associated with # the top level namespace. # @param [Symbol, String] name the name (or complex path) of the object. # @yield [self] a block to perform any extra initialization on the object # @yieldparam [Base] self the newly initialized code object # @return [Base] the newly created object def initialize(namespace, name, *args, &block) if namespace && namespace != :root && !namespace.is_a?(NamespaceObject) && !namespace.is_a?(Proxy) raise ArgumentError, "Invalid namespace object: #{namespace}" end @files = [] @current_file_has_comments = false @name = name.to_sym @source_type = :ruby @visibility = :public @tags = [] @docstrings = {} @docstring = Docstring.new('', self) @namespace = nil self.namespace = namespace yield(self) if block_given? end # Copies all data in this object to another code object, except for # uniquely identifying information (path, namespace, name, scope). # # @param [Base] other the object to copy data to # @return [Base] the other object # @since 0.8.0 def copy_to(other) copyable_attributes.each do |ivar| ivar = "@#{ivar}" other.instance_variable_set(ivar, instance_variable_get(ivar)) end other.docstring = @docstring.to_raw other end # The name of the object # @param [Boolean] prefix whether to show a prefix. Implement # this in a subclass to define how the prefix is showed. # @return [Symbol] if prefix is false, the symbolized name # @return [String] if prefix is true, prefix + the name as a String. # This must be implemented by the subclass. def name(prefix = false) prefix ? @name.to_s : @name end # Associates a file with a code object, optionally adding the line where it was defined. # By convention, '' should be used to associate code that comes form standard input. # # @param [String] file the filename ('' for standard input) # @param [Fixnum, nil] line the line number where the object lies in the file # @param [Boolean] has_comments whether or not the definition has comments associated. This # will allow {#file} to return the definition where the comments were made instead # of any empty definitions that might have been parsed before (module namespaces for instance). def add_file(file, line = nil, has_comments = false) raise(ArgumentError, "file cannot be nil or empty") if file.nil? || file == '' obj = [file.to_s, line] return if files.include?(obj) if has_comments && !@current_file_has_comments @current_file_has_comments = true @files.unshift(obj) else @files << obj # back of the line end end # Returns the filename the object was first parsed at, taking # definitions with docstrings first. # # @return [String] a filename def file @files.first ? @files.first[0] : nil end # Returns the line the object was first parsed at (or nil) # # @return [Fixnum] the line where the object was first defined. # @return [nil] if there is no line associated with the object def line @files.first ? @files.first[1] : nil end # Tests if another object is equal to this, including a proxy # @param [Base, Proxy] other if other is a {Proxy}, tests if # the paths are equal # @return [Boolean] whether or not the objects are considered the same def equal?(other) if other.is_a?(Base) || other.is_a?(Proxy) path == other.path else super end end alias == equal? alias eql? equal? # @return [Integer] the object's hash value (for equality checking) def hash; path.hash end # @return [nil] this object does not turn into an array def to_ary; nil end # Accesses a custom attribute on the object # @param [#to_s] key the name of the custom attribute # @return [Object, nil] the custom attribute or nil if not found. # @see #[]= def [](key) if respond_to?(key) send(key) elsif instance_variable_defined?("@#{key}") instance_variable_get("@#{key}") end end # Sets a custom attribute on the object # @param [#to_s] key the name of the custom attribute # @param [Object] value the value to associate # @return [void] # @see #[] def []=(key, value) if respond_to?("#{key}=") send("#{key}=", value) else instance_variable_set("@#{key}", value) end end # @overload dynamic_attr_name # @return the value of attribute named by the method attribute name # @raise [NoMethodError] if no method or custom attribute exists by # the attribute name # @see #[] # @overload dynamic_attr_name=(value) # @param value a value to set # @return +value+ # @see #[]= def method_missing(meth, *args, &block) if meth.to_s =~ /=$/ self[meth.to_s[0..-2]] = args.first elsif instance_variable_get("@#{meth}") self[meth] else super end end # Attaches source code to a code object with an optional file location # # @param [#source, String] statement # the +Parser::Statement+ holding the source code or the raw source # as a +String+ for the definition of the code object only (not the block) def source=(statement) if statement.respond_to?(:source) self.signature = statement.first_line @source = format_source(statement.source.strip) else @source = format_source(statement.to_s) end end # The documentation string associated with the object # # @param [String, I18n::Locale] locale (I18n::Locale.default) # the locale of the documentation string. # @return [Docstring] the documentation string def docstring(locale = I18n::Locale.default) if locale.nil? @docstring.resolve_reference return @docstring end if locale.is_a?(String) locale_name = locale locale = nil else locale_name = locale.name end @docstrings[locale_name] ||= translate_docstring(locale || Registry.locale(locale_name)) end # Attaches a docstring to a code object by parsing the comments attached to the statement # and filling the {#tags} and {#docstring} methods with the parsed information. # # @param [String, Array, Docstring] comments # the comments attached to the code object to be parsed # into a docstring and meta tags. def docstring=(comments) @docstrings.clear if Docstring === comments @docstring = comments else @docstring = Docstring.new(comments, self) end end # Default type is the lowercase class name without the "Object" suffix. # Override this method to provide a custom object type # # @return [Symbol] the type of code object this represents def type self.class.name.split('::').last.gsub(/Object$/, '').downcase.to_sym end # Represents the unique path of the object. The default implementation # joins the path of {#namespace} with {#name} via the value of {#sep}. # Custom code objects should ensure that the path is unique to the code # object by either overriding {#sep} or this method. # # @example The path of an instance method # MethodObject.new(P("A::B"), :c).path # => "A::B#c" # @return [String] the unique path of the object # @see #sep def path @path ||= if parent && !parent.root? [parent.path, name.to_s].join(sep) else name.to_s end end alias_method :to_s, :path # @note # Override this method if your object has a special title that does # not match the {#path} attribute value. This title will be used # when linking or displaying the object. # @return [String] the display title for an object # @see 0.8.4 def title path end # @param [Base, String] other another code object (or object path) # @return [String] the shortest relative path from this object to +other+ # @since 0.5.3 def relative_path(other) other = Registry.at(other) if String === other && Registry.at(other) same_parent = false if other.respond_to?(:path) same_parent = other.parent == parent other = other.path end return other unless namespace common = [path, other].join(" ").match(/^(\S*)\S*(?: \1\S*)*$/)[1] common = path unless common =~ /(\.|::|#)$/ common = common.sub(/(\.|::|#)[^:#\.]*?$/, '') if same_parent if %w(. :).include?(common[-1,1]) || other[common.size,1] == '#' suffix = '' else suffix = '(::|\.)' end result = other.sub(/^#{Regexp.quote common}#{suffix}/, '') result.empty? ? other : result end # Renders the object using the {Templates::Engine templating system}. # # @example Formats a class in plaintext # puts P('MyClass').format # @example Formats a method in html with rdoc markup # puts P('MyClass#meth').format(:format => :html, :markup => :rdoc) # @param [Hash] options a set of options to pass to the template # @option options [Symbol] :format (:text) :html, :text or another output format # @option options [Symbol] :template (:default) a specific template to use # @option options [Symbol] :markup (nil) the markup type (:rdoc, :markdown, :textile) # @option options [Serializers::Base] :serializer (nil) see Serializers # @return [String] the rendered template # @see Templates::Engine#render def format(options = {}) options = options.merge(:object => self) Templates::Engine.render(options) end # Inspects the object, returning the type and path # @return [String] a string describing the object def inspect "#" end # Sets the namespace the object is defined in. # # @param [NamespaceObject, :root, nil] obj the new namespace (:root # for {Registry.root}). If obj is nil, the object is unregistered # from the Registry. def namespace=(obj) if @namespace @namespace.children.delete(self) Registry.delete(self) end @namespace = (obj == :root ? Registry.root : obj) if @namespace reg_obj = Registry.at(path) return if reg_obj && reg_obj.class == self.class @namespace.children << self unless @namespace.is_a?(Proxy) Registry.register(self) end end alias_method :parent, :namespace alias_method :parent=, :namespace= # Gets a tag from the {#docstring} # @see Docstring#tag def tag(name); docstring.tag(name) end # Gets a list of tags from the {#docstring} # @see Docstring#tags def tags(name = nil); docstring.tags(name) end # Tests if the {#docstring} has a tag # @see Docstring#has_tag? def has_tag?(name); docstring.has_tag?(name) end # Add tags to the {#docstring} # @see Docstring#add_tag # @since 0.8.4 def add_tag(*tags) @docstrings.clear @docstring.add_tag(*tags) end # @return whether or not this object is a RootObject def root?; false end # Override this method with a custom component separator. For instance, # {MethodObject} implements sep as '#' or '.' (depending on if the # method is instance or class respectively). {#path} depends on this # value to generate the full path in the form: namespace.path + sep + name # # @return [String] the component that separates the namespace path # and the name (default is {NSEP}) def sep; NSEP end protected # Override this method if your code object subclass does not allow # copying of certain attributes. # # @return [Array] the list of instance variable names (without # "@" prefix) that should be copied when {#copy_to} is called # @see #copy_to # @since 0.8.0 def copyable_attributes vars = instance_variables.map {|ivar| ivar.to_s[1..-1] } vars -= %w(docstring docstrings namespace name path) vars end private # Formats source code by removing leading indentation # # @param [String] source the source code to format # @return [String] formatted source def format_source(source) source.chomp! last = source.split(/\r?\n/).last indent = last ? last[/^([ \t]*)/, 1].length : 0 source.gsub(/^[ \t]{#{indent}}/, '') end def translate_docstring(locale) @docstring.resolve_reference return @docstring if locale.nil? text = I18n::Text.new(@docstring) localized_text = text.translate(locale) docstring = Docstring.new(localized_text, self) docstring.add_tag(*@docstring.tags) docstring end end end end yard-0.8.7.3/lib/yard/code_objects/namespace_object.rb0000644000004100000410000001647012261240652022625 0ustar www-datawww-datamodule YARD::CodeObjects # A "namespace" is any object that can store other objects within itself. # The two main Ruby objects that can act as namespaces are modules # ({ModuleObject}) and classes ({ClassObject}). class NamespaceObject < Base attr_writer :constants, :cvars, :mixins, :child, :meths attr_writer :class_attributes, :instance_attributes attr_writer :included_constants, :included_meths # @return [Array] a list of ordered group names inside the namespace # @since 0.6.0 attr_accessor :groups # The list of objects defined in this namespace # @return [Array] a list of objects attr_reader :children # A hash containing two keys, class and instance, each containing # the attribute name with a { :read, :write } hash for the read and # write objects respectively. # # @example The attributes of an object # >> Registry.at('YARD::Docstring').attributes # => { # :class => { }, # :instance => { # :ref_tags => { # :read => #, # :write => nil # }, # :object => { # :read => #, # :write => # # }, # ... # } # } # @return [Hash] a list of methods attr_reader :attributes # A hash containing two keys, :class and :instance, each containing # a hash of objects and their alias names. # @return [Hash] a list of methods attr_reader :aliases # Class mixins # @return [Array] a list of mixins attr_reader :class_mixins # Instance mixins # @return [Array] a list of mixins attr_reader :instance_mixins # Creates a new namespace object inside +namespace+ with +name+. # @see Base#initialize def initialize(namespace, name, *args, &block) @children = CodeObjectList.new(self) @class_mixins = CodeObjectList.new(self) @instance_mixins = CodeObjectList.new(self) @attributes = SymbolHash[:class => SymbolHash.new, :instance => SymbolHash.new] @aliases = {} @groups = [] super end # Only the class attributes # @return [Hash] a list of method names and their read/write objects # @see #attributes def class_attributes attributes[:class] end # Only the instance attributes # @return [Hash] a list of method names and their read/write objects # @see #attributes def instance_attributes attributes[:instance] end # Looks for a child that matches the attributes specified by +opts+. # # @example Finds a child by name and scope # namespace.child(:name => :to_s, :scope => :instance) # # => # # @return [Base, nil] the first matched child object, or nil def child(opts = {}) if !opts.is_a?(Hash) children.find {|o| o.name == opts.to_sym } else opts = SymbolHash[opts] children.find do |obj| opts.each do |meth, value| break false if !(value.is_a?(Array) ? value.include?(obj[meth]) : obj[meth] == value) end end end end # Returns all methods that match the attributes specified by +opts+. If # no options are provided, returns all methods. # # @example Finds all private and protected class methods # namespace.meths(:visibility => [:private, :protected], :scope => :class) # # => [#, #] # @option opts [Array, Symbol] :visibility ([:public, :private, # :protected]) the visibility of the methods to list. Can be an array or # single value. # @option opts [Array, Symbol] :scope ([:class, :instance]) the # scope of the methods to list. Can be an array or single value. # @option opts [Boolean] :included (true) whether to include mixed in # methods in the list. # @return [Array] a list of method objects def meths(opts = {}) opts = SymbolHash[ :visibility => [:public, :private, :protected], :scope => [:class, :instance], :included => true ].update(opts) opts[:visibility] = [opts[:visibility]].flatten opts[:scope] = [opts[:scope]].flatten ourmeths = children.select do |o| o.is_a?(MethodObject) && opts[:visibility].include?(o.visibility) && opts[:scope].include?(o.scope) end ourmeths + (opts[:included] ? included_meths(opts) : []) end # Returns methods included from any mixins that match the attributes # specified by +opts+. If no options are specified, returns all included # methods. # # @option opts [Array, Symbol] :visibility ([:public, :private, # :protected]) the visibility of the methods to list. Can be an array or # single value. # @option opts [Array, Symbol] :scope ([:class, :instance]) the # scope of the methods to list. Can be an array or single value. # @option opts [Boolean] :included (true) whether to include mixed in # methods in the list. # @see #meths def included_meths(opts = {}) opts = SymbolHash[:scope => [:instance, :class]].update(opts) [opts[:scope]].flatten.map do |scope| mixins(scope).inject([]) do |list, mixin| next list if mixin.is_a?(Proxy) arr = mixin.meths(opts.merge(:scope => :instance)).reject do |o| next false if opts[:all] child(:name => o.name, :scope => scope) || list.find {|o2| o2.name == o.name } end arr.map! {|o| ExtendedMethodObject.new(o) } if scope == :class list + arr end end.flatten end # Returns all constants in the namespace # # @option opts [Boolean] :included (true) whether or not to include # mixed in constants in list # @return [Array] a list of constant objects def constants(opts = {}) opts = SymbolHash[:included => true].update(opts) consts = children.select {|o| o.is_a? ConstantObject } consts + (opts[:included] ? included_constants : []) end # Returns constants included from any mixins # @return [Array] a list of constant objects def included_constants instance_mixins.inject([]) do |list, mixin| if mixin.respond_to? :constants list += mixin.constants.reject do |o| child(:name => o.name) || list.find {|o2| o2.name == o.name } end else list end end end # Returns class variables defined in this namespace. # @return [Array] a list of class variable objects def cvars children.select {|o| o.is_a? ClassVariableObject } end # Returns for specific scopes. If no scopes are provided, returns all mixins. # @param [Array] scopes a list of scopes (:class, :instance) to # return mixins for. If this is empty, all scopes will be returned. # @return [Array] a list of mixins def mixins(*scopes) return class_mixins if scopes == [:class] return instance_mixins if scopes == [:instance] class_mixins | instance_mixins end end end yard-0.8.7.3/lib/yard/docstring_parser.rb0000644000004100000410000002520712261240652020266 0ustar www-datawww-datarequire 'ostruct' module YARD # Parses text and creates a {Docstring} object to represent documentation # for a {CodeObjects::Base}. To create a new docstring, you should initialize # the parser and call {#parse} followed by {#to_docstring}. # # == Subclassing Notes # # The DocstringParser can be subclassed and subtituted during parsing by # setting the {Docstring.default_parser} attribute with the name of the # subclass. This allows developers to change the way docstrings are # parsed, allowing for completely different docstring syntaxes. # # @example Creating a Docstring with a DocstringParser # DocstringParser.new.parse("text here").to_docstring # @example Creating a Custom DocstringParser # # Parses docstrings backwards! # class ReverseDocstringParser # def parse_content(content) # super(content.reverse) # end # end # # # Set the parser as default when parsing # YARD::Docstring.default_parser = ReverseDocstringParser # @see #parse_content # @since 0.8.0 class DocstringParser # @return [String] the parsed text portion of the docstring, # with tags removed. attr_accessor :text # @return [String] the complete input string to the parser. attr_accessor :raw_text # @return [Array] the list of meta-data tags identified # by the parser attr_accessor :tags # @return [Array] a list of directives identified # by the parser. This list will not be passed on to the # Docstring object. attr_accessor :directives # @return [OpenStruct] any arbitrary state to be passed between # tags during parsing. Mainly used by directives to coordinate # behaviour (so that directives can be aware of other directives # used in a docstring). attr_accessor :state # @return [CodeObjects::Base, nil] the object associated with # the docstring being parsed. May be nil if the docstring is # not attached to any object. attr_accessor :object # @return [CodeObjects::Base, nil] the object referenced by # the docstring being parsed. May be nil if the docstring doesn't # refer to any object. attr_accessor :reference # @return [Handlers::Base, nil] the handler parsing this # docstring. May be nil if this docstring parser is not # initialized through attr_accessor :handler # @return [Tags::Library] the tag library being used to # identify registered tags in the docstring. attr_accessor :library # The regular expression to match the tag syntax META_MATCH = /^@(!)?((?:\w\.?)+)(?:\s+(.*))?$/i # @!group Creation and Conversion Methods # Creates a new parser to parse docstring data # # @param [Tags::Library] library a tag library for recognizing # tags. def initialize(library = Tags::Library.instance) @text = "" @raw_text = "" @tags = [] @directives = [] @library = library @object = nil @reference = nil @handler = nil @state = OpenStruct.new end # @return [Docstring] translates parsed text into # a Docstring object. def to_docstring Docstring.new!(text, tags, object, raw_text, reference) end # @!group Parsing Methods # Parses all content and returns itself. # # @param [String] content the docstring text to parse # @param [CodeObjects::Base] object the object that the docstring # is attached to. Will be passed to directives to act on # this object. # @param [Handlers::Base, nil] handler the handler object that is # parsing this object. May be nil if this parser is not being # called from a {Parser::SourceParser} context. # @return [self] the parser object. To get the docstring, # call {#to_docstring}. # @see #to_docstring def parse(content, object = nil, handler = nil) @object = object @handler = handler @reference, @raw_text = detect_reference(content) text = parse_content(@raw_text) # Remove trailing/leading whitespace / newlines @text = text.gsub(/\A[\r\n\s]+|[\r\n\s]+\Z/, '') call_directives_after_parse call_after_parse_callbacks self end # Parses a given block of text. # # @param [String] content the content to parse # @note Subclasses can override this method to perform custom # parsing of content data. def parse_content(content) content = content.split(/\r?\n/) if content.is_a?(String) return '' if !content || content.empty? docstring = "" indent, last_indent = content.first[/^\s*/].length, 0 orig_indent = 0 directive = false last_line = "" tag_name, tag_klass, tag_buf = nil, nil, [] (content+['']).each_with_index do |line, index| indent = line[/^\s*/].length empty = (line =~ /^\s*$/ ? true : false) done = content.size == index if tag_name && (((indent < orig_indent && !empty) || done || (indent == 0 && !empty)) || (indent <= last_indent && line =~ META_MATCH)) buf = tag_buf.join("\n") if directive || tag_is_directive?(tag_name) directive = create_directive(tag_name, buf) if directive docstring << parse_content(directive.expanded_text).chomp end else create_tag(tag_name, buf) end tag_name, tag_buf, directive = nil, [], false orig_indent = 0 end # Found a meta tag if line =~ META_MATCH directive, tag_name, tag_buf = $1, $2, [($3 || '')] elsif tag_name && indent >= orig_indent && !empty orig_indent = indent if orig_indent == 0 # Extra data added to the tag on the next line last_empty = last_line =~ /^[ \t]*$/ ? true : false tag_buf << '' if last_empty tag_buf << line.gsub(/^[ \t]{#{orig_indent}}/, '') elsif !tag_name # Regular docstring text docstring << line << "\n" end last_indent = indent last_line = line end docstring end # @!group Tag Manipulation Methods # Creates a tag from the {Tags::DefaultFactory tag factory}. # # To add an already created tag object, append it to {#tags}. # # @param [String] tag_name the tag name # @param [String] tag_buf the text attached to the tag with newlines removed. # @return [Tags::Tag, Tags::RefTag] a tag def create_tag(tag_name, tag_buf = '') if tag_buf =~ /\A\s*(?:(\S+)\s+)?\(\s*see\s+(\S+)\s*\)\s*\Z/ return create_ref_tag(tag_name, $1, $2) end if library.has_tag?(tag_name) @tags += [library.tag_create(tag_name, tag_buf)].flatten else log.warn "Unknown tag @#{tag_name}" + (object ? " in file `#{object.file}` near line #{object.line}" : "") end rescue Tags::TagFormatError log.warn "Invalid tag format for @#{tag_name}" + (object ? " in file `#{object.file}` near line #{object.line}" : "") end # Creates a {Tags::RefTag} def create_ref_tag(tag_name, name, object_name) @tags << Tags::RefTagList.new(tag_name, P(object, object_name), name) end # Creates a new directive using the registered {#library} # @return [Directive] the directive object that is created def create_directive(tag_name, tag_buf) if library.has_directive?(tag_name) dir = library.directive_create(tag_name, tag_buf, self) if dir.is_a?(Tags::Directive) @directives << dir dir end else log.warn "Unknown directive @!#{tag_name}" + (object ? " in file `#{object.file}` near line #{object.line}" : "") nil end rescue Tags::TagFormatError log.warn "Invalid directive format for @!#{tag_name}" + (object ? " in file `#{object.file}` near line #{object.line}" : "") nil end # Backward compatibility to detect old tags that should be specified # as directives in 0.8 and onward. def tag_is_directive?(tag_name) list = %w(attribute endgroup group macro method scope visibility) list.include?(tag_name) end private def namespace if object object.namespace else nil end end def detect_reference(content) if content =~ /\A\s*\(see (\S+)\s*\)(?:\s|$)/ path, extra = $1, $' [CodeObjects::Proxy.new(namespace, path), extra] else [nil, content] end end # @!group Parser Callback Methods # Calls the {Directive#after_parse} callback on all the # created directives. def call_directives_after_parse directives.each do |dir| dir.after_parse end end # Calls all {after_parse} callbacks def call_after_parse_callbacks self.class.after_parse_callbacks.each do |cb| cb.call(self) end end public # Creates a callback that is called after a docstring is successfully # parsed. Use this method to perform sanity checks on a docstring's # tag data, or add any extra tags automatically to a docstring. # # @yield [parser] a block to be called after a docstring is parsed # @yieldparam [DocstringParser] parser the docstring parser object # with all directives and tags created. # @yieldreturn [void] # @return [void] def self.after_parse(&block) self.after_parse_callbacks << block end # @return [Array] the {after_parse} callback proc objects def self.after_parse_callbacks @after_parse_callbacks ||= [] end # Define a callback to check that @param tags are properly named after_parse do |parser| next unless parser.object next unless parser.object.is_a?(CodeObjects::MethodObject) next if parser.object.parameters.empty? # method has no params or # YARD couldn't detect any. # but don't warn user (?) names = parser.object.parameters.map {|l| l.first.gsub(/\W/, '') } seen_names = [] infile_info = "\n in file `#{parser.object.file}' " + "near line #{parser.object.line}" parser.tags.each do |tag| next if tag.is_a?(Tags::RefTagList) # we don't handle this yet next unless tag.tag_name == "param" if seen_names.include?(tag.name) log.warn "@param tag has duplicate parameter name: " + "#{tag.name} #{infile_info}" elsif names.include?(tag.name) seen_names << tag.name else log.warn "@param tag has unknown parameter name: " + "#{tag.name} #{infile_info}" end end end end end yard-0.8.7.3/lib/yard/registry.rb0000644000004100000410000004010412261240652016557 0ustar www-datawww-datarequire 'fileutils' require 'digest/sha1' module YARD # The +Registry+ is the centralized data store for all {CodeObjects} created # during parsing. The storage is a key value store with the object's path # (see {CodeObjects::Base#path}) as the key and the object itself as the value. # Object paths must be unique to be stored in the Registry. All lookups for # objects are done on the singleton Registry instance using the {Registry.at} # or {Registry.resolve} methods. # # == Saving / Loading a Registry # The registry is saved to a "yardoc file" (actually a directory), which can # be loaded back to perform any lookups. See {Registry.load!} and # {Registry.save} for information on saving and loading of a yardoc file. # # == Threading Notes # The registry class is a singleton class that is accessed directly in many # places across YARD. To mitigate threading issues, YARD (0.6.5+) makes # the Registry thread local. This means all access to a registry for a specific # object set must occur in the originating thread. # # @example Loading the Registry # Registry.load!('/path/to/yardocfile') # loads all objects into memory # Registry.at('YARD::CodeObjects::Base').docstring # # => "+Base+ is the superclass of all code objects ..." # @example Getting an object by a specific path # Registry.at('YARD::CodeObjects::Base#docstring') # @example Performing a lookup on a method anywhere in the inheritance tree # Registry.resolve(P('YARD::CodeObjects::Base'), '#docstring', true) module Registry DEFAULT_YARDOC_FILE = ".yardoc" LOCAL_YARDOC_INDEX = File.expand_path('~/.yard/gem_index') DEFAULT_PO_DIR = "po" extend Enumerable class << self # @group Getting .yardoc File Locations # Returns the .yardoc file associated with a gem. # # @param [String] gem the name of the gem to search for # @param [String] ver_require an optional Gem version requirement # @param [Boolean] for_writing whether or not the method should search # for writable locations # @return [String] if +for_writing+ is set to +true+, returns the best # location suitable to write the .yardoc file. Otherwise, the first # existing location associated with the gem's .yardoc file. # @return [nil] if +for_writing+ is set to false and no yardoc file # is found, returns nil. def yardoc_file_for_gem(gem, ver_require = ">= 0", for_writing = false) spec = Gem.source_index.find_name(gem, ver_require) return if spec.empty? spec = spec.first if gem =~ /^yard-doc-/ path = File.join(spec.full_gem_path, DEFAULT_YARDOC_FILE) return File.exist?(path) && !for_writing ? path : nil end if for_writing global_yardoc_file(spec, for_writing) || local_yardoc_file(spec, for_writing) else local_yardoc_file(spec, for_writing) || global_yardoc_file(spec, for_writing) end end # Gets/sets the yardoc filename # @return [String] the yardoc filename # @see DEFAULT_YARDOC_FILE attr_accessor :yardoc_file undef yardoc_file, yardoc_file= def yardoc_file=(v) Thread.current[:__yard_yardoc_file__] = v end def yardoc_file Thread.current[:__yard_yardoc_file__] ||= DEFAULT_YARDOC_FILE end # @group Loading Data from Disk # Loads the registry and/or parses a list of files # # @example Loads the yardoc file or parses files 'a', 'b' and 'c' (but not both) # Registry.load(['a', 'b', 'c']) # @example Reparses files 'a' and 'b' regardless of whether yardoc file exists # Registry.load(['a', 'b'], true) # @param [String, Array] files if +files+ is an Array, it should represent # a list of files that YARD should parse into the registry. If reload is # set to false and the yardoc file already exists, these files are skipped. # If files is a String, it should represent the yardoc file to load # into the registry. # @param [Boolean] reparse if reparse is false and a yardoc file already # exists, any files passed in will be ignored. # @return [Registry] the registry object (for chaining) # @raise [ArgumentError] if files is not a String or Array def load(files = [], reparse = false) if files.is_a?(Array) if File.exist?(yardoc_file) && !reparse load_yardoc else size = thread_local_store.keys.size YARD.parse(files) save if thread_local_store.keys.size > size end elsif files.is_a?(String) load_yardoc(files) else raise ArgumentError, "Must take a list of files to parse or the .yardoc file to load." end self end # Loads a yardoc file directly # # @param [String] file the yardoc file to load. # @return [Registry] the registry object (for chaining) def load_yardoc(file = yardoc_file) clear thread_local_store.load(file) self end # Loads a yardoc file and forces all objects cached on disk into # memory. Equivalent to calling {load_yardoc} followed by {load_all} # # @param [String] file the yardoc file to load # @return [Registry] the registry object (for chaining) # @see #load_yardoc # @see #load_all # @since 0.5.1 def load!(file = yardoc_file) clear thread_local_store.load!(file) self end # Forces all objects cached on disk into memory # # @example Loads all objects from disk # Registry.load # Registry.all.count #=> 0 # Registry.load_all # Registry.all.count #=> 17 # @return [Registry] the registry object (for chaining) # @since 0.5.1 def load_all thread_local_store.load_all self end # @group Saving and Deleting Data from Disk # Saves the registry to +file+ # # @param [String] file the yardoc file to save to # @return [Boolean] true if the file was saved def save(merge = false, file = yardoc_file) thread_local_store.save(merge, file) end # Deletes the yardoc file from disk # @return [void] def delete_from_disk thread_local_store.destroy end # @group Adding and Deleting Objects from the Registry # Registers a new object with the registry # # @param [CodeObjects::Base] object the object to register # @return [CodeObjects::Base] the registered object def register(object) return if object.is_a?(CodeObjects::Proxy) thread_local_store[object.path] = object end # Deletes an object from the registry # @param [CodeObjects::Base] object the object to remove # @return [void] def delete(object) thread_local_store.delete(object.path) end # Clears the registry # @return [void] def clear self.thread_local_store = RegistryStore.new end # @group Accessing Objects in the Registry # Iterates over {all} with no arguments def each(&block) all.each(&block) end # Returns all objects in the registry that match one of the types provided # in the +types+ list (if +types+ is provided). # # @example Returns all objects # Registry.all # @example Returns all classes and modules # Registry.all(:class, :module) # @param [Array] types an optional list of types to narrow the # objects down by. Equivalent to performing a select: # +Registry.all.select {|o| types.include(o.type) }+ # @return [Array] the list of objects found # @see CodeObjects::Base#type def all(*types) if types.empty? thread_local_store.values.select {|obj| obj != root } else list = [] types.each do |type| list += thread_local_store.values_for_type(type) end list end end # Returns the paths of all of the objects in the registry. # @param [Boolean] reload whether to load entire database # @return [Array] all of the paths in the registry. def paths(reload = false) thread_local_store.keys(reload).map {|k| k.to_s } end # Returns the object at a specific path. # @param [String, :root] path the pathname to look for. If +path+ is +root+, # returns the {root} object. # @return [CodeObjects::Base] the object at path # @return [nil] if no object is found def at(path) path ? thread_local_store[path] : nil end alias_method :[], :at # The root namespace object. # @return [CodeObjects::RootObject] the root object in the namespace def root; thread_local_store[:root] end # @param [String] name the locale name. # @return [I18n::Locale] the locale object for +name+. # @since 0.8.3 def locale(name) thread_local_store.locale(name) end # Attempts to find an object by name starting at +namespace+, performing # a lookup similar to Ruby's method of resolving a constant in a namespace. # # @example Looks for instance method #reverse starting from A::B::C # Registry.resolve(P("A::B::C"), "#reverse") # @example Looks for a constant in the root namespace # Registry.resolve(nil, 'CONSTANT') # @example Looks for a class method respecting the inheritance tree # Registry.resolve(myclass, 'mymethod', true) # @example Looks for a constant but returns a proxy if not found # Registry.resolve(P('A::B::C'), 'D', false, true) # => # # @example Looks for a complex path from a namespace # Registry.resolve(P('A::B'), 'B::D') # => # # @param [CodeObjects::NamespaceObject, nil] namespace the starting namespace # (module or class). If +nil+ or +:root+, starts from the {root} object. # @param [String, Symbol] name the name (or complex path) to look for from # +namespace+. # @param [Boolean] inheritance Follows inheritance chain (mixins, superclass) # when performing name resolution if set to +true+. # @param [Boolean] proxy_fallback If +true+, returns a proxy representing # the unresolved path (namespace + name) if no object is found. # @param [Symbol, nil] type the {CodeObjects::Base#type} that the resolved # object must be equal to. No type checking if nil. # @return [CodeObjects::Base] the object if it is found # @return [CodeObjects::Proxy] a Proxy representing the object if # +proxy_fallback+ is +true+. # @return [nil] if +proxy_fallback+ is +false+ and no object was found. # @see P def resolve(namespace, name, inheritance = false, proxy_fallback = false, type = nil) if namespace.is_a?(CodeObjects::Proxy) return proxy_fallback ? CodeObjects::Proxy.new(namespace, name, type) : nil end if namespace == :root || !namespace namespace = root else namespace = namespace.parent until namespace.is_a?(CodeObjects::NamespaceObject) end orignamespace = namespace name = name.to_s if name =~ /^#{CodeObjects::NSEPQ}/ [name, name[2..-1]].each do |n| found = at(n) return found if found && (type.nil? || found.type == type) end else while namespace if namespace.is_a?(CodeObjects::NamespaceObject) if inheritance nss = namespace.inheritance_tree(true) if namespace.respond_to?(:superclass) if namespace.superclass != P('BasicObject') nss |= [P('Object')] end nss |= [P('BasicObject')] end else nss = [namespace] end nss.each do |ns| next if ns.is_a?(CodeObjects::Proxy) found = partial_resolve(ns, name, type) return found if found end end namespace = namespace.parent end end proxy_fallback ? CodeObjects::Proxy.new(orignamespace, name, type) : nil end # @group Managing Source File Checksums # @return [Hash{String => String}] a set of checksums for files def checksums thread_local_store.checksums end # @param [String] data data to checksum # @return [String] the SHA1 checksum for data def checksum_for(data) Digest::SHA1.hexdigest(data) end # @group Managing Internal State (Advanced / Testing Only) # Whether or not the Registry storage should load everything into a # single object database (for disk efficiency), or spread them out # (for load time efficiency). # # @note Setting this attribute to nil will offload the decision to # the {RegistryStore storage adapter}. # @return [Boolean, nil] if this value is set to nil, the storage # adapter will decide how to store the data. attr_accessor :single_object_db undef single_object_db, single_object_db= def single_object_db=(v) Thread.current[:__yard_single_db__] = v end def single_object_db; Thread.current[:__yard_single_db__] end # The assumed types of a list of paths. This method is used by CodeObjects::Base # @return [{String => Symbol}] a set of unresolved paths and their assumed type # @private # @deprecated The registry no longer globally tracks proxy types. def proxy_types thread_local_store.proxy_types end # @group I18n features # Gets/sets the directory that has LANG.po files # @return [String] the directory that has .po files attr_accessor :po_dir undef po_dir, po_dir= def po_dir=(dir) Thread.current[:__yard_po_dir__] = dir end def po_dir Thread.current[:__yard_po_dir__] ||= DEFAULT_PO_DIR end # @group Legacy Methods # The registry singleton instance. # # @deprecated use Registry.methodname directly. # @return [Registry] returns the registry instance def instance; self end private # @group Accessing Objects in the Registry # Attempts to resolve a name in a namespace # # @param [CodeObjects::NamespaceObject] namespace the starting namespace # @param [String] name the name to look for # @param [Symbol, nil] type the {CodeObjects::Base#type} that the resolved # object must be equal to def partial_resolve(namespace, name, type = nil) obj = at(name) || at('#' + name) if namespace.root? return obj if obj && (type.nil? || obj.type == type) [CodeObjects::NSEP, CodeObjects::CSEP, ''].each do |s| next if s.empty? && name =~ /^\w/ path = name if namespace != root path = [namespace.path, name].join(s) end found = at(path) return found if found && (type.nil? || found.type == type) end nil end # @group Retrieving yardoc File Locations def global_yardoc_file(spec, for_writing = false) path = spec.full_gem_path yfile = File.join(path, DEFAULT_YARDOC_FILE) if for_writing && File.writable?(path) return yfile elsif !for_writing && File.exist?(yfile) return yfile end end def local_yardoc_file(spec, for_writing = false) path = Registry::LOCAL_YARDOC_INDEX FileUtils.mkdir_p(path) if for_writing path = File.join(path, "#{spec.full_name}.yardoc") if for_writing path else File.exist?(path) ? path : nil end end # @group Threading support # @since 0.6.5 def thread_local_store Thread.current[:__yard_registry__] ||= clear end # @since 0.6.5 def thread_local_store=(value) Thread.current[:__yard_registry__] = value end end end end yard-0.8.7.3/lib/yard/cli/0000755000004100000410000000000012261240652015132 5ustar www-datawww-datayard-0.8.7.3/lib/yard/cli/diff.rb0000644000004100000410000002040512261240652016370 0ustar www-datawww-datarequire 'tmpdir' require 'fileutils' require 'open-uri' module YARD module CLI # CLI command to return the objects that were added/removed from 2 versions # of a project (library, gem, working copy). # @since 0.6.0 class Diff < Command def initialize super @list_all = false @use_git = false @compact = false @modified = true @verifier = Verifier.new @old_git_commit = nil @old_path = Dir.pwd log.show_backtraces = true end def description 'Returns the object diff of two gems or .yardoc files' end def run(*args) registry = optparse(*args).map do |gemfile| if @use_git load_git_commit(gemfile) all_objects else if load_gem_data(gemfile) log.info "Found #{gemfile}" all_objects else log.error "Cannot find gem #{gemfile}" nil end end end.compact return if registry.size != 2 first_object = nil [ ["Added objects", "A", added_objects(*registry)], ["Modified objects", "M", modified_objects(*registry)], ["Removed objects", "D", removed_objects(*registry)]].each do |name, short, objects| next if short == "M" && @modified == false next if objects.empty? last_object = nil all_objects_notice = false log.puts name + ":" unless @compact objects.sort_by {|o| o.path }.each do |object| if !@list_all && last_object && object.parent == last_object log.print " (...)" unless all_objects_notice all_objects_notice = true next elsif @compact log.puts if first_object else log.puts end all_objects_notice = false log.print "" + (@compact ? "#{short} " : " ") + object.path + " (#{object.file}:#{object.line})" last_object = object first_object = true end unless @compact log.puts; log.puts end end log.puts if @compact end private def all_objects return Registry.all if @verifier.expressions.empty? @verifier.run(Registry.all) end def added_objects(registry1, registry2) registry2.reject {|o| registry1.find {|o2| o2.path == o.path } } end def modified_objects(registry1, registry2) registry1.select do |obj| case obj when CodeObjects::MethodObject registry2.find {|o| obj == o && o.source != obj.source } when CodeObjects::ConstantObject registry2.find {|o| obj == o && o.value != obj.value } end end.compact end def removed_objects(registry1, registry2) registry1.reject {|o| registry2.find {|o2| o2.path == o.path } } end def load_git_commit(commit) Registry.clear commit_path = 'git_commit' + commit.gsub(/\W/, '_') tmpdir = File.join(Dir.tmpdir, commit_path) log.info "Expanding #{commit} to #{tmpdir}..." Dir.chdir(@old_path) FileUtils.mkdir_p(tmpdir) FileUtils.cp_r('.', tmpdir) Dir.chdir(tmpdir) log.info("git says: " + `git reset --hard #{commit}`.chomp) generate_yardoc(tmpdir) ensure Dir.chdir(@old_path) cleanup(commit_path) end def load_gem_data(gemfile) require_rubygems Registry.clear # First check for argument as .yardoc file [File.join(gemfile, '.yardoc'), gemfile].each do |yardoc| log.info "Searching for .yardoc db at #{yardoc}" if File.directory?(yardoc) Registry.load_yardoc(yardoc) Registry.load_all return true end end # Next check installed RubyGems gemfile_without_ext = gemfile.sub(/\.gem$/, '') log.info "Searching for installed gem #{gemfile_without_ext}" Gem.source_index.find_name('').find do |spec| if spec.full_name == gemfile_without_ext if yardoc = Registry.yardoc_file_for_gem(spec.name, "= #{spec.version}") Registry.load_yardoc(yardoc) Registry.load_all else log.enter_level(Logger::ERROR) do olddir = Dir.pwd Gems.run(spec.name, spec.version.to_s) Dir.chdir(olddir) end end return true end end # Look for local .gem file gemfile += '.gem' unless gemfile =~ /\.gem$/ log.info "Searching for local gem file #{gemfile}" if File.exist?(gemfile) File.open(gemfile, 'rb') do |io| expand_and_parse(gemfile, io) end return true end # Remote gemfile from rubygems.org url = "http://rubygems.org/downloads/#{gemfile}" log.info "Searching for remote gem file #{url}" begin open(url) {|io| expand_and_parse(gemfile, io) } return true rescue OpenURI::HTTPError end false end def expand_and_parse(gemfile, io) dir = expand_gem(gemfile, io) generate_yardoc(dir) cleanup(gemfile) end def generate_yardoc(dir) olddir = Dir.pwd Dir.chdir(dir) do log.enter_level(Logger::ERROR) { Yardoc.run('-n', '--no-save') } end end def expand_gem(gemfile, io) tmpdir = File.join(Dir.tmpdir, gemfile) FileUtils.mkdir_p(tmpdir) log.info "Expanding #{gemfile} to #{tmpdir}..." if Gem::VERSION >= '2.0.0' require 'rubygems/package/tar_reader' reader = Gem::Package::TarReader.new(io) reader.each do |pkg| if pkg.full_name == 'data.tar.gz' Zlib::GzipReader.wrap(pkg) do |gzio| tar = Gem::Package::TarReader.new(gzio) tar.each do |entry| mode = entry.header.mode file = File.join(tmpdir, entry.full_name) FileUtils.mkdir_p(File.dirname(file)) File.open(file, 'wb') do |out| out.write(entry.read) out.fsync rescue nil end end end break end end else Gem::Package.open(io) do |pkg| pkg.each do |entry| pkg.extract_entry(tmpdir, entry) end end end tmpdir end def require_rubygems require 'rubygems' require 'rubygems/package' rescue LoadError => e log.error "Missing RubyGems, cannot run this command." raise(e) end def cleanup(gemfile) dir = File.join(Dir.tmpdir, gemfile) log.info "Cleaning up #{dir}..." FileUtils.rm_rf(dir) end def optparse(*args) opts = OptionParser.new opts.banner = "Usage: yard diff [options] oldgem newgem" opts.separator "" opts.separator "Example: yard diff yard-0.5.6 yard-0.5.8" opts.separator "" opts.separator "If the files don't exist locally, they will be grabbed using the `gem fetch`" opts.separator "command. If the gem is a .yardoc directory, it will be used. Finally, if the" opts.separator "gem name matches an installed gem (full name-version syntax), that gem will be used." opts.on('-a', '--all', 'List all objects, even if they are inside added/removed module/class') do @list_all = true end opts.on('--compact', 'Show compact results') { @compact = true } opts.on('--git', 'Compare versions from two git commit/branches') do @use_git = true end opts.on('--query QUERY', 'Only diff filtered objects') do |query| @verifier.add_expressions(query) end opts.on('--no-modified', 'Ignore modified objects') do @modified = false end common_options(opts) parse_options(opts, args) unless args.size == 2 log.puts opts.banner exit(0) end args end end end end yard-0.8.7.3/lib/yard/cli/display.rb0000644000004100000410000000360712261240652017132 0ustar www-datawww-datamodule YARD module CLI # Display one object # @since 0.8.6 class Display < Yardoc def description; 'Displays a formatted object' end def initialize(*args) super options.format = :text # default for this command @layout = nil @objects = [] end # Runs the commandline utility, parsing arguments and displaying an object # from the {Registry}. # # @param [Array] args the list of arguments. # @return [void] def run(*args) return unless parse_arguments(*args) log.puts wrap_layout(format_objects) end # @return [String] the output data for all formatted objects def format_objects @objects.inject([]) do |arr, obj| arr.push obj.format(options) end.join("\n") end def wrap_layout(contents) return contents unless @layout opts = options.merge( :contents => contents, :object => @objects.first, :objects => @objects ) args = [options.template, @layout, options.format] Templates::Engine.template(*args).run(opts) end # Parses commandline options. # @param [Array] args each tokenized argument def parse_arguments(*args) opts = OptionParser.new opts.banner = "Usage: yard display [options] OBJECT [OTHER OBJECTS]" general_options(opts) output_options(opts) parse_options(opts, args) Registry.load @objects = args.map {|o| Registry.at(o) } # validation return false if @objects.any? {|o| o.nil? } verify_markup_options end def output_options(opts) super(opts) opts.on('-l', '--layout [LAYOUT]', 'Wraps output in layout template (good for HTML)') do |layout| @layout = layout || 'layout' end end end end end yard-0.8.7.3/lib/yard/cli/markup_types.rb0000644000004100000410000000201312261240652020176 0ustar www-datawww-datamodule YARD module CLI # Lists all markup types # @since 0.8.6 class MarkupTypes < Command def description; 'Lists all available markup types and libraries' end # Runs the commandline utility, parsing arguments and displaying a # list of markup types # # @param [Array] args the list of arguments. # @return [void] def run(*args) log.puts "Available markup types for `doc' command:" log.puts types = Templates::Helpers::MarkupHelper::MARKUP_PROVIDERS exts = Templates::Helpers::MarkupHelper::MARKUP_EXTENSIONS types.sort_by {|name, _| name.to_s }.each do |name, providers| log.puts "[#{name}]" libs = providers.map {|p| p[:lib] }.compact if libs.size > 0 log.puts " Providers: #{libs.join(" ")}" end if exts[name] log.puts " Extensions: #{exts[name].map {|e| ".#{e}"}.join(" ")}" end log.puts end end end end end yard-0.8.7.3/lib/yard/cli/command_parser.rb0000644000004100000410000000516512261240652020460 0ustar www-datawww-datamodule YARD module CLI # This class parses a command name out of the +yard+ CLI command and calls # that command in the form: # # $ yard command_name [options] # # If no command or arguments are specified, or if the arguments immediately # begin with a +--opt+ (not +--help+), the {default_command} will be used # (which itself defaults to +:doc+). # # == Adding a Command # # To add a custom command via plugin, create a mapping in {commands} from # the Symbolic command name to the {Command} class that implements the # command. To implement a command, see the documentation for the {Command} # class. # # @see Command # @see commands # @see default_command class CommandParser class << self # @return [Hash{Symbol => Command}] the mapping of command names to # command classes to parse the user command. attr_accessor :commands # @return [Symbol] the default command name to use when no options # are specified or attr_accessor :default_command end self.commands = SymbolHash[ :config => Config, :diff => Diff, :display => Display, :doc => Yardoc, :gems => Gems, :graph => Graph, :help => Help, :list => List, :markups => MarkupTypes, :ri => YRI, :server => Server, :stats => Stats, :i18n => I18n ] self.default_command = :doc # Convenience method to create a new CommandParser and call {#run} # @return (see #run) def self.run(*args) new.run(*args) end def initialize log.show_backtraces = false end # Runs the {Command} object matching the command name of the first # argument. # @return [void] def run(*args) unless args == ['--help'] if args.size == 0 || args.first =~ /^-/ command_name = self.class.default_command else command_name = args.first.to_sym args.shift end if commands.has_key?(command_name) return commands[command_name].run(*args) end end list_commands end private def commands; self.class.commands end def list_commands log.puts "Usage: yard [options]" log.puts log.puts "Commands:" commands.keys.sort_by {|k| k.to_s }.each do |command_name| command = commands[command_name].new log.puts "%-8s %s" % [command_name, command.description] end end end end end yard-0.8.7.3/lib/yard/cli/yardoc.rb0000644000004100000410000006411012261240652016742 0ustar www-datawww-datarequire 'digest/sha1' require 'fileutils' module YARD module CLI # Default options used in +yard doc+ command. class YardocOptions < Templates::TemplateOptions # @return [Array] # the list of extra files rendered along with objects default_attr :files, lambda { [] } # @return [String] the default title appended to each generated page default_attr :title, "Documentation by YARD #{YARD::VERSION}" # @return [Verifier] the default verifier object to filter queries default_attr :verifier, lambda { Verifier.new } # @return [Serializers::Base] the default serializer for generating output # to disk. default_attr :serializer, lambda { Serializers::FileSystemSerializer.new } # @return [Symbol] the default output format (:html). default_attr :format, :html # @return [Boolean] whether the data should be rendered in a single page, # if the template supports it. default_attr :onefile, false # @return [CodeObjects::ExtraFileObject] the README file object rendered # along with objects attr_accessor :readme # @return [Array] the list of code objects to render # the templates with. attr_accessor :objects # @return [Numeric] An index value for rendering sequentially related templates attr_accessor :index # @return [CodeObjects::Base] an extra item to send to a template that is not # the main rendered object attr_accessor :item # @return [CodeObjects::ExtraFileObject] the file object being rendered. # The +object+ key is not used so that a file may be rendered in the context # of an object's namespace (for generating links). attr_accessor :file end # Yardoc is the default YARD CLI command (+yard doc+ and historic +yardoc+ # executable) used to generate and output (mainly) HTML documentation given # a set of source files. # # == Usage # # Main usage for this command is: # # $ yardoc [options] [source_files [- extra_files]] # # See +yardoc --help+ for details on valid options. # # == Options File (+.yardopts+) # # If a +.yardopts+ file is found in the source directory being processed, # YARD will use the contents of the file as arguments to the command, # treating newlines as spaces. You can use shell-style quotations to # group space delimited arguments, just like on the command line. # # A valid +.yardopts+ file might look like: # # --no-private # --title "My Title" # --exclude foo --exclude bar # lib/**/*.erb # lib/**/*.rb - # HACKING.rdoc LEGAL COPYRIGHT # # Note that Yardoc also supports the legacy RDoc style +.document+ file, # though this file can only specify source globs to parse, not options. # # == Queries (+--query+) # # Yardoc supports queries to select specific code objects for which to # generate documentation. For example, you might want to generate # documentation only for your public API. If you've documented your public # methods with +@api public+, you can use the following query to select # all of these objects: # # --query '@api.text == "public"' # # Note that the syntax for queries is mostly Ruby with a few syntactic # simplifications for meta-data tags. See the {Verifier} class for an # overview of this syntax. # # == Adding Custom Ad-Hoc Meta-data Tags (+--tag+) # # YARD allows specification of {file:docs/Tags.md meta-data tags} # programmatically via the {YARD::Tags::Library} class, but often this is not # practical for users writing documentation. To make adding custom tags # easier, Yardoc has a few command-line switches for creating basic tags # and displaying them in generated HTML output. # # To specify a custom tag to be displayed in output, use any of the # following: # # * +--tag+ TAG:TITLE # * +--name-tag+ TAG:TITLE # * +--type-tag+ TAG:TITLE # * +--type-name-tag+ TAG:TITLE # * +--title-tag+ TAG:TITLE # # "TAG:TITLE" is of the form: name:"Display Title", for example: # # --tag overload:"Overloaded Method" # # See +yardoc --help+ for a description of the various options. # # Tags added in this way are automatically displayed in output. To add # a meta-data tag that does not show up in output, use +--hide-tag TAG+. # Note that you can also use this option on existing tags to hide # builtin tags, for instance. # # == Processed Data Storage (+.yardoc+ directory) # # When Yardoc parses a source directory, it creates a +.yardoc+ directory # (by default, override with +-b+) at the root of the project. This directory # contains marshal dumps for all raw object data in the source, so that # you can access it later for various commands (+stats+, +graph+, etc.). # This directory is also used as a cache for any future calls to +yardoc+ # so as to process only the files which have changed since the last call. # # When Yardoc uses the cache in subsequent calls to +yardoc+, methods # or classes that have been deleted from source since the last parsing # will not be erased from the cache (YARD never deletes objects). In such # a case, you should wipe the cache and do a clean parsing of the source tree. # You can do this by deleting the +.yardoc+ directory manually, or running # Yardoc without +--use-cache+ (+-c+). # # @since 0.2.1 # @see Verifier class Yardoc < YardoptsCommand # @return [Hash] the hash of options passed to the template. # @see Templates::Engine#render attr_reader :options # @return [Array] list of Ruby source files to process attr_accessor :files # @return [Array] list of excluded paths (regexp matches) # @since 0.5.3 attr_accessor :excluded # @return [Boolean] whether to use the existing yardoc db if the # .yardoc already exists. Also makes use of file checksums to # parse only changed files. attr_accessor :use_cache # @return [Boolean] whether objects should be serialized to .yardoc db attr_accessor :save_yardoc # @return [Boolean] whether to generate output attr_accessor :generate # @return [Boolean] whether to print a list of objects # @since 0.5.5 attr_accessor :list # Keep track of which visibilities are to be shown # @return [Array] a list of visibilities # @since 0.5.6 attr_accessor :visibilities # Keep track of which APIs are to be shown # @return [Array] a list of APIs # @since 0.8.1 attr_accessor :apis # Keep track of which APIs are to be hidden # @return [Array] a list of APIs to be hidden # @since 0.8.7 attr_accessor :hidden_apis # @return [Array] a list of tags to hide from templates # @since 0.6.0 attr_accessor :hidden_tags # @return [Boolean] whether to print statistics after parsing # @since 0.6.0 attr_accessor :statistics # @return [Array] a list of assets to copy after generation # @since 0.6.0 attr_accessor :assets # @return [Boolean] whether markup option was specified # @since 0.7.0 attr_accessor :has_markup # Creates a new instance of the commandline utility def initialize super @options = YardocOptions.new @options.reset_defaults @visibilities = [:public] @apis = [] @hidden_apis = [] @assets = {} @excluded = [] @files = [] @hidden_tags = [] @use_cache = false @generate = true @statistics = true @list = false @save_yardoc = true @has_markup = false if defined?(::Encoding) && ::Encoding.respond_to?(:default_external=) ::Encoding.default_external, ::Encoding.default_internal = 'utf-8', 'utf-8' end end def description "Generates documentation" end # Runs the commandline utility, parsing arguments and generating # output if set. # # @param [Array] args the list of arguments. If the list only # contains a single nil value, skip calling of {#parse_arguments} # @return [void] def run(*args) log.show_progress = true if args.size == 0 || !args.first.nil? # fail early if arguments are not valid return unless parse_arguments(*args) end checksums = nil if use_cache Registry.load checksums = Registry.checksums.dup end YARD.parse(files, excluded) Registry.save(use_cache) if save_yardoc if generate run_generate(checksums) copy_assets elsif list print_list end if !list && statistics && log.level < Logger::ERROR Registry.load_all log.enter_level(Logger::ERROR) do Stats.new(false).run(*args) end end true ensure log.show_progress = false end # Parses commandline arguments # @param [Array] args the list of arguments # @return [Boolean] whether or not arguments are valid # @since 0.5.6 def parse_arguments(*args) super(*args) # Last minute modifications self.files = ['{lib,app}/**/*.rb', 'ext/**/*.c'] if self.files.empty? self.files.delete_if {|x| x =~ /\A\s*\Z/ } # remove empty ones readme = Dir.glob('README*').first readme ||= Dir.glob(files.first).first if options.onefile options.readme ||= CodeObjects::ExtraFileObject.new(readme) if readme options.files.unshift(options.readme).uniq! if options.readme Tags::Library.visible_tags -= hidden_tags add_visibility_verifier add_api_verifier apply_locale # US-ASCII is invalid encoding for onefile if defined?(::Encoding) && options.onefile if ::Encoding.default_internal == ::Encoding::US_ASCII log.warn "--one-file is not compatible with US-ASCII encoding, using ASCII-8BIT" ::Encoding.default_external, ::Encoding.default_internal = ['ascii-8bit'] * 2 end end if generate && !verify_markup_options false else true end end # The list of all objects to process. Override this method to change # which objects YARD should generate documentation for. # # @deprecated To hide methods use the +@private+ tag instead. # @return [Array] a list of code objects to process def all_objects Registry.all(:root, :module, :class) end private # Generates output for objects # @param [Hash, nil] checksums if supplied, a list of checkums for files. # @return [void] # @since 0.5.1 def run_generate(checksums) if checksums changed_files = [] Registry.checksums.each do |file, hash| changed_files << file if checksums[file] != hash end end Registry.load_all if use_cache objects = run_verifier(all_objects).reject do |object| serialized = !options.serializer || options.serializer.exists?(object) if checksums && serialized && !object.files.any? {|f, line| changed_files.include?(f) } true else log.debug "Re-generating object #{object.path}..." false end end Templates::Engine.generate(objects, options) end # Verifies that the markup options are valid before parsing any code. # Failing early is better than failing late. # # @return (see YARD::Templates::Helpers::MarkupHelper#load_markup_provider) def verify_markup_options result, lvl = false, has_markup ? log.level : Logger::FATAL obj = Struct.new(:options).new(options) obj.extend(Templates::Helpers::MarkupHelper) options.files.each do |file| markup = file.attributes[:markup] || obj.markup_for_file('', file.filename) result = obj.load_markup_provider(markup) return false if !result && markup != :rdoc end options.markup = :rdoc unless has_markup log.enter_level(lvl) { result = obj.load_markup_provider } if !result && !has_markup log.warn "Could not load default RDoc formatter, " + "ignoring any markup (install RDoc to get default formatting)." options.markup = :none true else result end end # Copies any assets to the output directory # @return [void] # @since 0.6.0 def copy_assets return unless options.serializer outpath = options.serializer.basepath assets.each do |from, to| to = File.join(outpath, to) log.debug "Copying asset '#{from}' to '#{to}'" from += '/.' if File.directory?(from) FileUtils.cp_r(from, to) end end # Prints a list of all objects # @return [void] # @since 0.5.5 def print_list Registry.load_all run_verifier(Registry.all). sort_by {|item| [item.file || '', item.line || 0] }.each do |item| log.puts "#{item.file}:#{item.line}: #{item.path}" end end # Adds a set of extra documentation files to be processed # @param [Array] files the set of documentation files def add_extra_files(*files) files.map! {|f| f.include?("*") ? Dir.glob(f) : f }.flatten! files.each do |file| if File.file?(file) options.files << CodeObjects::ExtraFileObject.new(file) else log.warn "Could not find extra file: #{file}" end end end # Parses the file arguments into Ruby files and extra files, which are # separated by a '-' element. # # @example Parses a set of Ruby source files # parse_files %w(file1 file2 file3) # @example Parses a set of Ruby files with a separator and extra files # parse_files %w(file1 file2 - extrafile1 extrafile2) # @param [Array] files the list of files to parse # @return [void] def parse_files(*files) seen_extra_files_marker = false files.each do |file| if file == "-" seen_extra_files_marker = true next end if seen_extra_files_marker add_extra_files(file) else self.files << file end end end # Adds verifier rule for visibilities # @return [void] # @since 0.5.6 def add_visibility_verifier vis_expr = "#{visibilities.uniq.inspect}.include?(object.visibility)" options.verifier.add_expressions(vis_expr) end # Adds verifier rule for APIs # @return [void] # @since 0.8.1 def add_api_verifier no_api = true if apis.delete('') exprs = [] if apis.size > 0 exprs << "#{apis.uniq.inspect}.include?(@api.text)" end if hidden_apis.size > 0 exprs << "!#{hidden_apis.uniq.inspect}.include?(@api.text)" end exprs = exprs.size > 0 ? [exprs.join(' && ')] : [] exprs << "!@api" if no_api expr = exprs.join(' || ') options.verifier.add_expressions(expr) unless expr.empty? end # Applies the specified locale to collected objects # @return [void] # @since 0.8.3 def apply_locale YARD::I18n::Locale.default = options.locale options.files.each do |file| file.locale = options.locale end end # (see Templates::Helpers::BaseHelper#run_verifier) def run_verifier(list) options.verifier ? options.verifier.run(list) : list end # @since 0.6.0 def add_tag(tag_data, factory_method = nil) tag, title = *tag_data.split(':') title ||= tag.capitalize Tags::Library.define_tag(title, tag.to_sym, factory_method) Tags::Library.visible_tags |= [tag.to_sym] end # Parses commandline options. # @param [Array] args each tokenized argument def optparse(*args) opts = OptionParser.new opts.banner = "Usage: yard doc [options] [source_files [- extra_files]]" opts.separator "(if a list of source files is omitted, " opts.separator " {lib,app}/**/*.rb ext/**/*.c is used.)" opts.separator "" opts.separator "Example: yardoc -o documentation/ - FAQ LICENSE" opts.separator " The above example outputs documentation for files in" opts.separator " lib/**/*.rb to documentation/ including the extra files" opts.separator " FAQ and LICENSE." opts.separator "" opts.separator "A base set of options can be specified by adding a .yardopts" opts.separator "file to your base path containing all extra options separated" opts.separator "by whitespace." general_options(opts) output_options(opts) tag_options(opts) common_options(opts) parse_options(opts, args) parse_files(*args) unless args.empty? end # Adds general options def general_options(opts) opts.separator "" opts.separator "General Options:" opts.on('-b', '--db FILE', 'Use a specified .yardoc db to load from or save to', ' (defaults to .yardoc)') do |yfile| YARD::Registry.yardoc_file = yfile end opts.on('--[no-]single-db', 'Whether code objects should be stored to single', ' database file (advanced)') do |use_single_db| Registry.single_object_db = use_single_db end opts.on('-n', '--no-output', 'Only generate .yardoc database, no documentation.') do self.generate = false end opts.on('-c', '--use-cache [FILE]', "Use the cached .yardoc db to generate documentation.", " (defaults to no cache)") do |file| YARD::Registry.yardoc_file = file if file self.use_cache = true end opts.on('--no-cache', "Clear .yardoc db before parsing source.") do self.use_cache = false end yardopts_options(opts) opts.on('--no-save', 'Do not save the parsed data to the yardoc db') do self.save_yardoc = false end opts.on('--exclude REGEXP', 'Ignores a file if it matches path match (regexp)') do |path| self.excluded << path end end # Adds output options def output_options(opts) opts.separator "" opts.separator "Output options:" opts.on('--one-file', 'Generates output as a single file') do options.onefile = true end opts.on('--list', 'List objects to standard out (implies -n)') do |format| self.generate = false self.list = true end opts.on('--no-public', "Don't show public methods. (default shows public)") do visibilities.delete(:public) end opts.on('--protected', "Show protected methods. (default hides protected)") do visibilities.push(:protected) end opts.on('--private', "Show private methods. (default hides private)") do visibilities.push(:private) end opts.on('--no-private', "Hide objects with @private tag") do options.verifier.add_expressions '!object.tag(:private) && (object.namespace.is_a?(CodeObjects::Proxy) || !object.namespace.tag(:private))' end opts.on('--[no-]api API', 'Generates documentation for a given API', '(objects which define the correct @api tag).', 'If --no-api is given, displays objects with', 'no @api tag.') do |api| api = '' if api == false apis.push(api) end opts.on('--hide-api API', 'Hides given @api tag from documentation') do |api| hidden_apis.push(api) end opts.on('--embed-mixins', "Embeds mixin methods into class documentation") do options.embed_mixins << '*' end opts.on('--embed-mixin [MODULE]', "Embeds mixin methods from a particular", " module into class documentation") do |mod| options.embed_mixins << mod end opts.on('--no-highlight', "Don't highlight code blocks in output.") do options.highlight = false end opts.on('--default-return TYPE', "Shown if method has no return type. ", " (defaults to 'Object')") do |type| options.default_return = type end opts.on('--hide-void-return', "Hides return types specified as 'void'. ", " (default is shown)") do options.hide_void_return = true end opts.on('--query QUERY', "Only show objects that match a specific query") do |query| next if YARD::Config.options[:safe_mode] options.verifier.add_expressions(query.taint) end opts.on('--title TITLE', 'Add a specific title to HTML documents') do |title| options.title = title end opts.on('-r', '--readme FILE', '--main FILE', 'The readme file used as the title page', ' of documentation.') do |readme| if File.file?(readme) options.readme = CodeObjects::ExtraFileObject.new(readme) else log.warn "Could not find readme file: #{readme}" end end opts.on('--files FILE1,FILE2,...', 'Any extra comma separated static files to be ', ' included (eg. FAQ)') do |files| add_extra_files(*files.split(",")) end opts.on('--asset FROM[:TO]', 'A file or directory to copy over to output ', ' directory after generating') do |asset| re = /^(?:\.\.\/|\/)/ from, to = *asset.split(':').map {|f| File.cleanpath(f) } to ||= from if from =~ re || to =~ re log.warn "Invalid file '#{asset}'" else assets[from] = to end end opts.on('-o', '--output-dir PATH', 'The output directory. (defaults to ./doc)') do |dir| options.serializer.basepath = dir end opts.on('-m', '--markup MARKUP', 'Markup style used in documentation, like textile, ', ' markdown or rdoc. (defaults to rdoc)') do |markup| self.has_markup = true options.markup = markup.to_sym end opts.on('-M', '--markup-provider MARKUP_PROVIDER', 'Overrides the library used to process markup ', ' formatting (specify the gem name)') do |markup_provider| options.markup_provider = markup_provider.to_sym end opts.on('--charset ENC', 'Character set to use when parsing files ', ' (default is system locale)') do |encoding| begin if defined?(Encoding) && Encoding.respond_to?(:default_external=) Encoding.default_external, Encoding.default_internal = encoding, encoding end rescue ArgumentError => e raise OptionParser::InvalidOption, e end end opts.on('-t', '--template TEMPLATE', 'The template to use. (defaults to "default")') do |template| options.template = template.to_sym end opts.on('-p', '--template-path PATH', 'The template path to look for templates in.', ' (used with -t).') do |path| next if YARD::Config.options[:safe_mode] YARD::Templates::Engine.register_template_path(File.expand_path(path)) end opts.on('-f', '--format FORMAT', 'The output format for the template.', ' (defaults to html)') do |format| options.format = format.to_sym end opts.on('--no-stats', 'Don\'t print statistics') do self.statistics = false end opts.on('--locale LOCALE', 'The locale for generated documentation.', ' (defaults to en)') do |locale| options.locale = locale end opts.on('--po-dir DIR', 'The directory that has .po files.', " (defaults to #{YARD::Registry.po_dir})") do |dir| YARD::Registry.po_dir = dir end end # Adds tag options # @since 0.6.0 def tag_options(opts) opts.separator "" opts.separator "Tag options: (TAG:TITLE looks like: 'overload:Overloaded Method')" opts.on('--tag TAG:TITLE', 'Registers a new free-form metadata @tag') do |tag| add_tag(tag) end opts.on('--type-tag TAG:TITLE', 'Tag with an optional types field') do |tag| add_tag(tag, :with_types) end opts.on('--type-name-tag TAG:TITLE', 'Tag with optional types and a name field') do |tag| add_tag(tag, :with_types_and_name) end opts.on('--name-tag TAG:TITLE', 'Tag with a name field') do |tag| add_tag(tag, :with_name) end opts.on('--title-tag TAG:TITLE', 'Tag with first line as title field') do |tag| add_tag(tag, :with_title_and_text) end opts.on('--hide-tag TAG', 'Hides a previously defined tag from templates') do |tag| self.hidden_tags |= [tag.to_sym] end opts.on('--transitive-tag TAG', 'Marks a tag as transitive') do |tag| Tags::Library.transitive_tags |= [tag.to_sym] end opts.on('--non-transitive-tag TAG', 'Marks a tag as not transitive') do |tag| Tags::Library.transitive_tags -= [tag.to_sym] end end end end end yard-0.8.7.3/lib/yard/cli/command.rb0000644000004100000410000000602312261240652017076 0ustar www-datawww-datarequire 'optparse' module YARD module CLI # Abstract base class for CLI utilities. Provides some helper methods for # the option parser # # @abstract # @since 0.6.0 class Command # Helper method to run the utility on an instance. # @see #run def self.run(*args) new.run(*args) end def description; '' end protected # Adds a set of common options to the tail of the OptionParser # # @param [OptionParser] opts the option parser object # @return [void] def common_options(opts) opts.separator "" opts.separator "Other options:" opts.on('-e', '--load FILE', 'A Ruby script to load before running command.') do |file| load_script(file) end opts.on('--plugin PLUGIN', 'Load a YARD plugin (gem with `yard-\' prefix)') do |name| # Not actually necessary to load here, this is done at boot in YARD::Config.load_plugins # YARD::Config.load_plugin(name) end opts.on('--legacy', 'Use old style Ruby parser and handlers. ', ' Always on in 1.8.x.') do YARD::Parser::SourceParser.parser_type = :ruby18 end opts.on('--safe', 'Enable safe mode for this instance') do # Parsed in YARD::Config.load end opts.on_tail('-q', '--quiet', 'Show no warnings.') { log.level = Logger::ERROR } opts.on_tail('--verbose', 'Show more information.') { log.level = Logger::INFO } opts.on_tail('--debug', 'Show debugging information.') { log.level = Logger::DEBUG } opts.on_tail('--backtrace', 'Show stack traces') { log.show_backtraces = true } opts.on_tail('-v', '--version', 'Show version.') { log.puts "yard #{YARD::VERSION}"; exit } opts.on_tail('-h', '--help', 'Show this help.') { log.puts opts; exit } end # Parses the option and gracefully handles invalid switches # # @param [OptionParser] opts the option parser object # @param [Array] args the arguments passed from input. This # array will be modified. # @return [void] def parse_options(opts, args) opts.parse!(args) rescue OptionParser::ParseError => err unrecognized_option(err) args.shift if args.first && args.first[0,1] != '-' retry end # Loads a Ruby script. If Config.options[:safe_mode] is enabled, # this method will do nothing. # # @param [String] file the path to the script to load # @since 0.6.2 def load_script(file) return if YARD::Config.options[:safe_mode] load(file) rescue LoadError => load_exception log.error "The file `#{file}' could not be loaded:\n#{load_exception}" exit end # Callback when an unrecognize option is parsed # # @param [OptionParser::ParseError] err the exception raised by the # option parser def unrecognized_option(err) log.warn "Unrecognized/#{err.message}" end end end endyard-0.8.7.3/lib/yard/cli/graph.rb0000644000004100000410000000747112261240652016571 0ustar www-datawww-datamodule YARD module CLI # Options to pass to the {Graph} CLI. class GraphOptions < Templates::TemplateOptions # @return [:dot] the default output format default_attr :format, :dot # @return [Boolean] whether to list the full class diagram attr_accessor :full # @return [Boolean] whether to show the object dependencies attr_accessor :dependencies # @return [String] any contents to pass to the digraph attr_accessor :contents end # A command-line utility to generate Graphviz graphs from # a set of objects # # @see Graph#run # @since 0.6.0 class Graph < YardoptsCommand # The options parsed out of the commandline. # Default options are: # :format => :dot attr_reader :options # The set of objects to include in the graph. attr_reader :objects # Creates a new instance of the command-line utility def initialize super @use_document_file = false @options = GraphOptions.new options.reset_defaults options.serializer = YARD::Serializers::StdoutSerializer.new end def description "Graphs class diagram using Graphviz" end # Runs the command-line utility. # # @example # grapher = Graph.new # grapher.run('--private') # @param [Array] args each tokenized argument def run(*args) parse_arguments(*args) contents = objects.map do |o| o.format(options.merge(:serialize => false)) end.join("\n") opts = {:type => :layout, :contents => contents} options.update(opts) Templates::Engine.render(options) end private def unrecognized_option(err) end # Parses commandline options. # @param [Array] args each tokenized argument def optparse(*args) visibilities = [:public] opts = OptionParser.new opts.separator "" opts.separator "General Options:" opts.on('-b', '--db FILE', 'Use a specified .yardoc db to load from or save to. (defaults to .yardoc)') do |yfile| YARD::Registry.yardoc_file = yfile end opts.on('--full', 'Full class diagrams (show methods and attributes).') do options[:full] = true end opts.on('-d', '--dependencies', 'Show mixins in dependency graph.') do options[:dependencies] = true end opts.on('--no-public', "Don't show public methods. (default shows public)") do visibilities.delete(:public) end opts.on('--protected', "Show or don't show protected methods. (default hides protected)") do visibilities.push(:protected) end opts.on('--private', "Show or don't show private methods. (default hides private)") do visibilities.push(:private) end opts.separator "" opts.separator "Output options:" opts.on('--dot [OPTIONS]', 'Send the results directly to `dot` with optional arguments.') do |dotopts| options.serializer = Serializers::ProcessSerializer.new('dot ' + dotopts.to_s) end opts.on('-f', '--file [FILE]', 'Writes output to a file instead of stdout.') do |file| options.serializer = Serializers::FileSystemSerializer.new(:basepath => '.', :extension => nil) options.serializer.instance_eval "def serialized_path(object) #{file.inspect} end" end common_options(opts) parse_options(opts, args) Registry.load expression = "#{visibilities.uniq.inspect}.include?(object.visibility)" options.verifier = Verifier.new(expression) if args.first @objects = args.map {|o| Registry.at(o) }.compact else @objects = [Registry.root] end end end end end yard-0.8.7.3/lib/yard/cli/help.rb0000644000004100000410000000067012261240652016412 0ustar www-datawww-datamodule YARD module CLI # Handles help for commands # @since 0.6.0 class Help < Command def description; "Retrieves help for a command" end def run(*args) if args.first && cmd = CommandParser.commands[args.first.to_sym] cmd.run('--help') else log.puts "Command #{args.first} not found." if args.first CommandParser.run('--help') end end end end endyard-0.8.7.3/lib/yard/cli/yri.rb0000644000004100000410000001455212261240652016271 0ustar www-datawww-datarequire 'rbconfig' module YARD module CLI # A tool to view documentation in the console like `ri` class YRI < Command # The location in {YARD::CONFIG_DIR} where the YRI cache file is loaded # from. CACHE_FILE = File.expand_path('~/.yard/yri_cache') # A file containing all paths, delimited by newlines, to search for # yardoc databases. # @since 0.5.1 SEARCH_PATHS_FILE = File.expand_path('~/.yard/yri_search_paths') # Default search paths that should be loaded dynamically into YRI. These paths # take precedence over all other paths ({SEARCH_PATHS_FILE} and RubyGems # paths). To add a path, call: # # DEFAULT_SEARCH_PATHS.push("/path/to/.yardoc") # # @return [Array] a list of extra search paths # @since 0.6.0 DEFAULT_SEARCH_PATHS = [] # Helper method to run the utility on an instance. # @see #run def self.run(*args) new.run(*args) end def initialize super @cache = {} @search_paths = [] add_default_paths add_gem_paths load_cache @search_paths.uniq! end def description "A tool to view documentation in the console like `ri`" end # Runs the command-line utility. # # @example # YRI.new.run('String#reverse') # @param [Array] args each tokenized argument def run(*args) optparse(*args) if ::RbConfig::CONFIG['host_os'] =~ /mingw|win32/ @serializer ||= YARD::Serializers::StdoutSerializer.new else @serializer ||= YARD::Serializers::ProcessSerializer.new('less') end if @name.nil? || @name.strip.empty? print_usage exit(1) elsif object = find_object(@name) print_object(object) else STDERR.puts "No documentation for `#{@name}'" exit(1) end end protected # Prints the command usage # @return [void] # @since 0.5.6 def print_usage log.puts "Usage: yri [options] " log.puts "See yri --help for more options." end # Caches the .yardoc file where an object can be found in the {CACHE_FILE} # @return [void] def cache_object(name, path) return if path == Registry.yardoc_file @cache[name] = path File.open!(CACHE_FILE, 'w') do |file| @cache.each do |key, value| file.puts("#{key} #{value}") end end end # @param [CodeObjects::Base] object the object to print. # @return [String] the formatted output for an object. def print_object(object) if object.type == :method && object.is_alias? tmp = P(object.namespace, (object.scope == :instance ? "#" : "") + object.namespace.aliases[object].to_s) object = tmp unless YARD::CodeObjects::Proxy === tmp end object.format(:serializer => @serializer) end # Locates an object by name starting in the cached paths and then # searching through any search paths. # # @param [String] name the full name of the object # @return [CodeObjects::Base] an object if found # @return [nil] if no object is found def find_object(name) @search_paths.unshift(@cache[name]) if @cache[name] @search_paths.unshift(Registry.yardoc_file) # Try to load it from in memory cache log.debug "Searching for #{name} in memory" if obj = try_load_object(name, nil) return obj end log.debug "Searching for #{name} in search paths" @search_paths.each do |path| next unless File.exist?(path) log.debug "Searching for #{name} in #{path}..." Registry.load(path) if obj = try_load_object(name, path) return obj end end nil end private # Tries to load the object with name. If successful, caches the object # with the cache_path # # @param [String] name the object path # @param [String] cache_path the location of the yardoc # db containing the object to cache for future lookups. # No caching is done if this is nil. # @return [void] def try_load_object(name, cache_path) if obj = Registry.at(name) if cache_path cache_object(name, cache_path) end return obj end end # Loads {CACHE_FILE} # @return [void] def load_cache return unless File.file?(CACHE_FILE) File.readlines(CACHE_FILE).each do |line| line = line.strip.split(/\s+/) @cache[line[0]] = line[1] end end # Adds all RubyGems yardoc files to search paths # @return [void] def add_gem_paths require 'rubygems' gem_paths = [] Gem.source_index.find_name('').each do |spec| if yfile = Registry.yardoc_file_for_gem(spec.name) if spec.name =~ /^yard-doc-/ gem_paths.unshift(yfile) else gem_paths.push(yfile) end end end @search_paths += gem_paths rescue LoadError end # Adds paths in {SEARCH_PATHS_FILE} # @since 0.5.1 def add_default_paths @search_paths.push(*DEFAULT_SEARCH_PATHS) return unless File.file?(SEARCH_PATHS_FILE) paths = File.readlines(SEARCH_PATHS_FILE).map {|l| l.strip } @search_paths.push(*paths) end # Parses commandline options. # @param [Array] args each tokenized argument def optparse(*args) opts = OptionParser.new opts.banner = "Usage: yri [options] " opts.separator "Example: yri String#gsub" opts.separator "" opts.separator "General Options:" opts.on('-b', '--db FILE', 'Use a specified .yardoc db to search in') do |yfile| @search_paths.unshift(yfile) end opts.on('-T', '--no-pager', 'No pager') do @serializer = YARD::Serializers::StdoutSerializer.new end opts.on('-p PAGER', '--pager') do |pager| @serializer = YARD::Serializers::ProcessSerializer.new(pager) end common_options(opts) parse_options(opts, args) @name = args.first end end end end yard-0.8.7.3/lib/yard/cli/config.rb0000644000004100000410000000751112261240652016730 0ustar www-datawww-datamodule YARD module CLI # CLI command to view or edit configuration options # @since 0.6.2 class Config < Command # @return [Symbol, nil] the key to view/edit, if any attr_accessor :key # @return [Array, nil] the list of values to set (or single value), if modifying attr_accessor :values # @return [Boolean] whether to reset the {#key} attr_accessor :reset # @return [Boolean] whether the value being set should be inside a list attr_accessor :as_list # @return [Boolean] whether to append values to existing key attr_accessor :append def initialize super self.key = nil self.values = [] self.reset = false self.append = false self.as_list = false end def description 'Views or edits current global configuration' end def run(*args) optparse(*args) if key if reset || values.size > 0 modify_item else view_item end else list_configuration end end private def modify_item if reset log.debug "Resetting #{key}" YARD::Config.options[key] = YARD::Config::DEFAULT_CONFIG_OPTIONS[key] else log.debug "Setting #{key} to #{values.inspect}" items, current_items = encode_values, YARD::Config.options[key] items = [current_items].flatten + [items].flatten if append YARD::Config.options[key] = items end YARD::Config.save end def view_item log.debug "Viewing #{key}" log.puts YARD::Config.options[key].inspect end def list_configuration log.debug "Listing configuration" require 'yaml' log.puts YAML.dump(YARD::Config.options).sub(/\A--.*\n/, '').gsub(/\n\n/, "\n") end def encode_values if values.size == 1 && !as_list encode_value(values.first) else values.map {|v| encode_value(v) } end end def encode_value(value) case value when /^-?\d+/; value.to_i when "true"; true when "false"; false else value end end def optparse(*args) list = false self.as_list = false self.append = false opts = OptionParser.new opts.banner = "Usage: yard config [options] [item [value ...]]" opts.separator "" opts.separator "Example: yard config load_plugins true" opts.separator "" opts.separator "Views and sets configuration items. If an item is provided" opts.separator "With no value, the item is viewed. If a value is provided," opts.separator "the item is modified. Specifying no item is equivalent to --list." opts.separator "If you specify multiple space delimited values, these are" opts.separator "parsed as an array of values." opts.separator "" opts.separator "Note that `true` and `false` are reserved words." opts.separator "" opts.separator "General options:" opts.on('-l', '--list', 'List current configuration') do list = true end opts.on('-r', '--reset', 'Resets the specific item to default') do self.reset = true end opts.separator "" opts.separator "Modifying keys:" opts.on('-a', '--append', 'Appends items to existing key values') do self.append = true end opts.on('--as-list', 'Forces the value(s) to be wrapped in an array') do self.as_list = true end common_options(opts) parse_options(opts, args) args = [] if list self.key = args.shift.to_sym if args.size >= 1 self.values = args if args.size >= 1 args end end end endyard-0.8.7.3/lib/yard/cli/list.rb0000644000004100000410000000125512261240652016435 0ustar www-datawww-datamodule YARD module CLI # Lists all constant and method names in the codebase. Uses {Yardoc} --list. class List < Command def description; 'Lists all constant and methods. Uses `yard doc --list`' end # Runs the commandline utility, parsing arguments and displaying a # list of objects # # @param [Array] args the list of arguments. # @return [void] def run(*args) if args.include?('--help') log.puts "Usage: yard list [yardoc_options]" log.puts "Takes the same arguments as yardoc. See yardoc --help" else Yardoc.run('-c', '--list', *args) end end end end endyard-0.8.7.3/lib/yard/cli/i18n.rb0000644000004100000410000000450612261240652016243 0ustar www-datawww-datarequire "pathname" module YARD module CLI # CLI command to support internationalization (a.k.a. i18n). # I18n feature is based on gettext technology. # This command generates .pot file from docstring and extra # documentation. # # @since 0.8.0 # @todo Support msgminit and msgmerge features? class I18n < Yardoc def initialize super @options.serializer.basepath = "po/yard.pot" end def description 'Generates .pot file from source code and extra documentation' end def run(*args) if args.size == 0 || !args.first.nil? # fail early if arguments are not valid return unless parse_arguments(*args) end YARD.parse(files, excluded) serializer = options.serializer pot_file_path = Pathname.new(serializer.basepath).expand_path pot_file_dir_path, pot_file_basename = pot_file_path.split relative_base_path = Pathname.pwd.relative_path_from(pot_file_dir_path) serializer.basepath = pot_file_dir_path.to_s serializer.serialize(pot_file_basename.to_s, generate_pot(relative_base_path.to_s)) true end private def general_options(opts) opts.banner = "Usage: yard i18n [options] [source_files [- extra_files]]" opts.top.list.clear opts.separator "(if a list of source files is omitted, " opts.separator " {lib,app}/**/*.rb ext/**/*.c is used.)" opts.separator "" opts.separator "Example: yard i18n -o yard.pot - FAQ LICENSE" opts.separator " The above example outputs .pot file for files in" opts.separator " lib/**/*.rb to yard.pot including the extra files" opts.separator " FAQ and LICENSE." opts.separator "" opts.separator "A base set of options can be specified by adding a .yardopts" opts.separator "file to your base path containing all extra options separated" opts.separator "by whitespace." super(opts) end def generate_pot(relative_base_path) generator = YARD::I18n::PotGenerator.new(relative_base_path) objects = run_verifier(all_objects) generator.parse_objects(objects) generator.parse_files(options.files || []) generator.generate end end end end yard-0.8.7.3/lib/yard/cli/gems.rb0000644000004100000410000000456412261240652016423 0ustar www-datawww-datamodule YARD module CLI # @since 0.6.0 class Gems < Command def initialize @rebuild = false @gems = [] end def description; "Builds YARD index for gems" end # Runs the commandline utility, parsing arguments and generating # YARD indexes for gems. # # @param [Array] args the list of arguments # @return [void] def run(*args) require 'rubygems' optparse(*args) build_gems end private # Builds .yardoc files for all non-existing gems # @param [Array] gems def build_gems require 'rubygems' @gems.each do |spec| ver = "= #{spec.version}" dir = Registry.yardoc_file_for_gem(spec.name, ver) if dir && File.directory?(dir) && !@rebuild log.debug "#{spec.name} index already exists at '#{dir}'" else yfile = Registry.yardoc_file_for_gem(spec.name, ver, true) next unless yfile next unless File.directory?(spec.full_gem_path) Registry.clear Dir.chdir(spec.full_gem_path) log.info "Building yardoc index for gem: #{spec.full_name}" Yardoc.run('--no-stats', '-n', '-b', yfile) end end end def add_gems(gems) 0.step(gems.size - 1, 2) do |index| gem, ver_require = gems[index], gems[index + 1] || ">= 0" specs = Gem.source_index.find_name(gem, ver_require) if specs.empty? log.warn "#{gem} #{ver_require} could not be found in RubyGems index" else @gems += specs end end end # Parses options def optparse(*args) opts = OptionParser.new opts.banner = 'Usage: yard gems [options] [gem_name [version]]' opts.separator "" opts.separator "#{description}. If no gem_name is given," opts.separator "all gems are built." opts.separator "" opts.on('--rebuild', 'Rebuilds index') do @rebuild = true end common_options(opts) parse_options(opts, args) add_gems(args) if !args.empty? && @gems.empty? log.error "No specified gems could be found for command" elsif @gems.empty? @gems += Gem.source_index.find_name('') if @gems.empty? end end end end endyard-0.8.7.3/lib/yard/cli/stats.rb0000644000004100000410000001500212261240652016613 0ustar www-datawww-datamodule YARD module CLI # @since 0.6.0 class Stats < Yardoc include Templates::Helpers::BaseHelper # Maintains the order in which +stats_for_+ statistics methods should be # printed. # # @see #print_statistics STATS_ORDER = [:files, :modules, :classes, :constants, :methods] # @return [Boolean] whether to parse and load registry attr_accessor :parse # @param [Boolean] parse whether to parse and load registry (see {#parse}) def initialize(parse = true) super() @parse = parse @undoc_list = nil @compact = false end def description "Prints documentation statistics on a set of files" end # Runs the commandline utility, parsing arguments and generating # output if set. # # @param [Array] args the list of arguments # @return [void] def run(*args) parse_arguments(*args) if use_cache Registry.load! elsif parse YARD.parse(files, excluded) Registry.save(use_cache) if save_yardoc end print_statistics print_undocumented_objects end # Prints statistics for different object types # # To add statistics for a specific type, add a method +#stats_for_TYPE+ # to this class that calls {#output}. def print_statistics @total, @undocumented = 0, 0 meths = methods.map {|m| m.to_s }.grep(/^stats_for_/) STATS_ORDER.each do |meth| mname = "stats_for_#{meth}" if meths.include?(mname) send(mname) meths.delete(mname) end end meths.each {|m| send(m) } if @total == 0 total = 0 else total = (@total - @undocumented).to_f / @total.to_f * 100 end log.puts("% 3.2f%% documented" % total) end # Prints list of undocumented objects def print_undocumented_objects return if !@undoc_list || @undoc_list.empty? log.puts log.puts "Undocumented Objects:" objects = @undoc_list.sort_by {|o| o.file } max = objects.sort_by {|o| o.path.length }.last.path.length if @compact objects.each do |object| log.puts("%-#{max}s (%s)" % [object.path, [object.file, object.line].compact.join(":")]) end else last_file = nil objects.each do |object| if object.file != last_file log.puts log.puts "(in file: #{object.file})" end log.puts object.path last_file = object.file end end end # @return [Array] all the parsed objects in the registry, # removing any objects that are not visible (private, protected) depending # on the arguments passed to the command. def all_objects @all_objects ||= run_verifier Registry.all end # Statistics for files def stats_for_files files = [] all_objects.each {|o| files |= [o.file] } output "Files", files.size end # Statistics for modules def stats_for_modules output "Modules", *type_statistics(:module) end # Statistics for classes def stats_for_classes output "Classes", *type_statistics(:class) end # Statistics for constants def stats_for_constants output "Constants", *type_statistics(:constant) end # Statistics for methods def stats_for_methods objs = all_objects.select {|m| m.type == :method } objs.reject! {|m| m.is_alias? || !m.is_explicit? } undoc = objs.select {|m| m.docstring.blank? && !m.overridden_method } @undoc_list |= undoc if @undoc_list output "Methods", objs.size, undoc.size end # Prints a statistic to standard out. This method is optimized for # getting Integer values, though it allows any data to be printed. # # @param [String] name the statistic name # @param [Integer, String] data the numeric (or any) data representing # the statistic. If +data+ is an Integer, it should represent the # total objects of a type. # @param [Integer, nil] undoc number of undocumented objects for the type # @return [void] def output(name, data, undoc = nil) @total += data if data.is_a?(Integer) && undoc @undocumented += undoc if undoc.is_a?(Integer) if undoc data = ("%5s (% 5d undocumented)" % [data, undoc]) else data = "%5s" % data end log.puts("%-12s %s" % [name + ":", data]) end private def type_statistics(type) objs = all_objects.select {|m| m.type == type } undoc = objs.find_all {|m| m.docstring.blank? } @undoc_list |= undoc if @undoc_list [objs.size, undoc.size] end # Parses commandline options. # @param [Array] args each tokenized argument def optparse(*args) opts = OptionParser.new opts.banner = "Usage: yard stats [options] [source_files]" opts.separator "(if a list of source files is omitted, lib/**/*.rb ext/**/*.c is used.)" general_options(opts) output_options(opts) tag_options(opts) common_options(opts) parse_options(opts, args) parse_files(*args) unless args.empty? end def general_options(opts) super(opts) opts.on('--list-undoc', 'List all undocumented objects') do @undoc_list = [] end opts.on('--compact', 'Compact undocumented objects listing') do @compact = true end opts.on('--no-public', "Don't include public methods in statistics.") do visibilities.delete(:public) end opts.on('--protected', "Include protected methods in statistics.") do visibilities.push(:protected) end opts.on('--private', "Include private methods in statistics.") do visibilities.push(:private) end opts.on('--no-private', "Don't include objects with @private tag in statistics.") do options[:verifier].add_expressions '!object.tag(:private) && (object.namespace.type == :proxy || !object.namespace.tag(:private))' end opts.on('--query QUERY', "Only includes objects that match a specific query") do |query| options[:verifier].add_expressions(query.taint) end end end end end yard-0.8.7.3/lib/yard/cli/yardopts_command.rb0000644000004100000410000000661212261240652021027 0ustar www-datawww-datarequire 'optparse' module YARD module CLI # Abstract base class for command that reads .yardopts file # # @abstract # @since 0.8.3 class YardoptsCommand < Command # The configuration filename to load extra options from DEFAULT_YARDOPTS_FILE = ".yardopts" # @return [Boolean] whether to parse options from .yardopts attr_accessor :use_yardopts_file # @return [Boolean] whether to parse options from .document attr_accessor :use_document_file # The options file name (defaults to {DEFAULT_YARDOPTS_FILE}) # @return [String] the filename to load extra options from attr_accessor :options_file # Creates a new command that reads .yardopts def initialize super @options_file = DEFAULT_YARDOPTS_FILE @use_yardopts_file = true @use_document_file = true end # Parses commandline arguments # @param [Array] args the list of arguments # @return [Boolean] whether or not arguments are valid # @since 0.5.6 def parse_arguments(*args) parse_yardopts_options(*args) # Parse files and then command line arguments parse_rdoc_document_file parse_yardopts optparse(*args) end protected # Adds --[no-]yardopts / --[no-]document def yardopts_options(opts) opts.on('--[no-]yardopts [FILE]', "If arguments should be read from FILE", " (defaults to yes, FILE defaults to .yardopts)") do |use_yardopts| if use_yardopts.is_a?(String) self.options_file = use_yardopts self.use_yardopts_file = true else self.use_yardopts_file = (use_yardopts != false) end end opts.on('--[no-]document', "If arguments should be read from .document file. ", " (defaults to yes)") do |use_document| self.use_document_file = use_document end end private # Parses the .yardopts file for default yard options # @return [Array] an array of options parsed from .yardopts def yardopts(file = options_file) return [] unless use_yardopts_file File.read_binary(file).shell_split rescue Errno::ENOENT [] end # Parses out the yardopts/document options def parse_yardopts_options(*args) opts = OptionParser.new opts.base.long.clear # HACK: why are --help and --version defined? yardopts_options(opts) begin opts.parse(args) rescue OptionParser::ParseError => err idx = args.index(err.args.first) args = args[(idx+1)..-1] args.shift while args.first && args.first[0,1] != '-' retry end end def parse_rdoc_document_file(file = '.document') optparse(*support_rdoc_document_file!(file)) if use_document_file end def parse_yardopts(file = options_file) optparse(*yardopts(file)) if use_yardopts_file end # Reads a .document file in the directory to get source file globs # @return [Array] an array of files parsed from .document def support_rdoc_document_file!(file = '.document') return [] unless use_document_file File.read(file).gsub(/^[ \t]*#.+/m, '').split(/\s+/) rescue Errno::ENOENT [] end end end end yard-0.8.7.3/lib/yard/cli/server.rb0000644000004100000410000002146512261240652016775 0ustar www-datawww-datamodule YARD module CLI # A local documentation server # @since 0.6.0 class Server < Command # @return [Hash] a list of options to pass to the doc server attr_accessor :options # @return [Hash] a list of options to pass to the web server attr_accessor :server_options # @return [Hash] a list of library names and yardoc files to serve attr_accessor :libraries # @return [Adapter] the adapter to use for loading the web server attr_accessor :adapter # @return [Array] a list of scripts to load # @since 0.6.2 attr_accessor :scripts # @return [Array] a list of template paths to register # @since 0.6.2 attr_accessor :template_paths # Creates a new instance of the Server command line utility def initialize super self.scripts = [] self.template_paths = [] self.libraries = {} self.options = SymbolHash.new(false).update( :single_library => true, :caching => false ) self.server_options = {:Port => 8808} end def description "Runs a local documentation server" end def run(*args) optparse(*args) select_adapter.setup load_scripts load_template_paths adapter.new(libraries, options, server_options).start end private def load_scripts scripts.each {|file| load_script(file) } end def load_template_paths return if YARD::Config.options[:safe_mode] Templates::Engine.template_paths |= template_paths end def select_adapter return adapter if adapter require 'rubygems' require 'rack' self.adapter = YARD::Server::RackAdapter rescue LoadError self.adapter = YARD::Server::WebrickAdapter end def add_libraries(args) (0...args.size).step(2) do |index| library, dir = args[index], args[index + 1] libver = nil if dir if File.exist?(dir) # Provided dir contains a .yardopts file libver = create_library_version_if_yardopts_exist(library, dir) libver ||= YARD::Server::LibraryVersion.new(library, nil, dir) end else # Check if this dir contains a .yardopts file pwd = Dir.pwd libver = create_library_version_if_yardopts_exist(library, pwd) # Check default location yfile = File.join(pwd, '.yardoc') libver ||= YARD::Server::LibraryVersion.new(library, nil, yfile) end # Register library if libver libver.yardoc_file = File.expand_path(libver.yardoc_file) if libver.yardoc_file libver.source_path = File.expand_path(libver.source_path) if libver.source_path libraries[library] ||= [] libraries[library] |= [libver] else log.warn "Cannot find yardoc db for #{library}: #{dir.inspect}" end end end # @param [String] library The library name. # @param [String, nil] dir The argument provided on the CLI after the # library name. Is supposed to point to either a project directory # with a Yard options file, or a yardoc db. # @return [LibraryVersion, nil] def create_library_version_if_yardopts_exist(library, dir) if dir options_file = File.join(dir, Yardoc::DEFAULT_YARDOPTS_FILE) if File.exist?(options_file) # Found yardopts, extract db path yfile = extract_db_from_options_file(options_file) db = File.expand_path(yfile, dir) # Create libver libver = YARD::Server::LibraryVersion.new(library, nil, db) libver.source_path = dir libver end end end def add_gems require 'rubygems' Gem.source_index.find_name('').each do |spec| libraries[spec.name] ||= [] libraries[spec.name] |= [YARD::Server::LibraryVersion.new(spec.name, spec.version.to_s, nil, :gem)] end end def add_gems_from_gemfile(gemfile = nil) require 'bundler' gemfile ||= "Gemfile" if File.exist?("#{gemfile}.lock") Bundler::LockfileParser.new(File.read("#{gemfile}.lock")).specs.each do |spec| libraries[spec.name] ||= [] libraries[spec.name] |= [YARD::Server::LibraryVersion.new(spec.name, spec.version.to_s, nil, :gem)] end else log.warn "Cannot find #{gemfile}.lock, ignoring --gemfile option" end rescue LoadError log.error "Bundler not available, ignoring --gemfile option" end def optparse(*args) opts = OptionParser.new opts.banner = 'Usage: yard server [options] [[library yardoc_file] ...]' opts.separator '' opts.separator 'Example: yard server -m yard .yardoc ruby-core ../ruby/.yardoc' opts.separator 'The above example serves documentation for YARD and Ruby-core' opts.separator '' opts.separator 'If no library/yardoc_file is specified, the server uses' opts.separator 'the name of the current directory and `.yardoc` respectively' opts.separator '' opts.separator "General Options:" opts.on('-m', '--multi-library', 'Serves documentation for multiple libraries') do options[:single_library] = false end opts.on('-c', '--cache', 'Caches all documentation to document root (see --docroot)') do options[:caching] = true end opts.on('-r', '--reload', 'Reparses the library code on each request') do options[:incremental] = true end opts.on('-g', '--gems', 'Serves documentation for installed gems') do add_gems end opts.on('-G', '--gemfile [GEMFILE]', 'Serves documentation for gems from Gemfile') do |gemfile| add_gems_from_gemfile(gemfile) end opts.on('-t', '--template-path PATH', 'The template path to look for templates in. (used with -t).') do |path| self.template_paths << path end opts.separator '' opts.separator "Web Server Options:" opts.on('-d', '--daemon', 'Daemonizes the server process') do server_options[:daemonize] = true end opts.on('-B HOST', '--bind', 'The host address to bind to') do |host| server_options[:Host] = host.to_s end opts.on('-p PORT', '--port', 'Serves documentation on PORT') do |port| server_options[:Port] = port.to_i end opts.on('--docroot DOCROOT', 'Uses DOCROOT as document root') do |docroot| server_options[:DocumentRoot] = File.expand_path(docroot) end opts.on('-a', '--adapter ADAPTER', 'Use the ADAPTER (full Ruby class) for web server') do |adapter| if adapter.downcase == 'webrick' self.adapter = YARD::Server::WebrickAdapter elsif adapter.downcase == 'rack' self.adapter = YARD::Server::RackAdapter else self.adapter = eval(adapter) end end opts.on('-s', '--server TYPE', 'Use a specific server type eg. thin,mongrel,cgi (Rack specific)') do |type| server_options[:server] = type end common_options(opts) opts.on('-e', '--load FILE', 'A Ruby script to load before the source tree is parsed.') do |file| self.scripts << file end parse_options(opts, args) if args.empty? && libraries.empty? # No args - try to use current dir add_libraries([File.basename(Dir.pwd), nil]) # Generate doc for first time libver = libraries.empty? ? nil : libraries.values.first.first if libver and !File.exist?(libver.yardoc_file) generate_doc_for_first_time(libver) end else add_libraries(args) options[:single_library] = false if libraries.size > 1 end end def generate_doc_for_first_time(libver) log.enter_level(Logger::INFO) do yardoc_file = libver.yardoc_file.sub /^#{Regexp.quote Dir.pwd}[\\\/]+/, '' log.info "No yardoc db found in #{yardoc_file}, parsing source before starting server..." end Dir.chdir(libver.source_path) do Yardoc.run('-n') end end def extract_db_from_options_file(options_file) args = File.read_binary(options_file).shell_split db = YARD::Registry.yardoc_file opts = OptionParser.new opts.on('-b', '--db FILE') {|file| db = file } begin opts.parse!(args) rescue OptionParser::ParseError args.shift if args.first && args.first[0,1] != '-' retry end db end end end end yard-0.8.7.3/lib/yard/server.rb0000644000004100000410000000045512261240652016222 0ustar www-datawww-datamodule YARD module Server # Registers a static path to be used in static asset lookup. # @param [String] path the pathname to register # @return [void] # @since 0.6.2 def self.register_static_path(path) Commands::StaticFileCommand::STATIC_PATHS.push(path) end end endyard-0.8.7.3/lib/yard/autoload.rb0000644000004100000410000003612212261240652016524 0ustar www-datawww-data# @private def __p(path) File.join(YARD::ROOT, 'yard', *path.split('/')); end module YARD module CLI # Namespace for command-line interface components autoload :Command, __p('cli/command') autoload :CommandParser, __p('cli/command_parser') autoload :Config, __p('cli/config') autoload :Diff, __p('cli/diff') autoload :Display, __p('cli/display') autoload :Gems, __p('cli/gems') autoload :Graph, __p('cli/graph') autoload :Help, __p('cli/help') autoload :List, __p('cli/list') autoload :MarkupTypes, __p('cli/markup_types') autoload :Server, __p('cli/server') autoload :Stats, __p('cli/stats') autoload :Yardoc, __p('cli/yardoc') autoload :YardoptsCommand, __p('cli/yardopts_command') autoload :YRI, __p('cli/yri') autoload :I18n, __p('cli/i18n') end # A "code object" is defined as any entity in the Ruby language. # Classes, modules, methods, class variables and constants are the # major objects, but DSL languages can create their own by inheriting # from {CodeObjects::Base}. module CodeObjects autoload :Base, __p('code_objects/base') autoload :CodeObjectList, __p('code_objects/base') autoload :ClassObject, __p('code_objects/class_object') autoload :ClassVariableObject, __p('code_objects/class_variable_object') autoload :ConstantObject, __p('code_objects/constant_object') autoload :ExtendedMethodObject, __p('code_objects/extended_method_object') autoload :ExtraFileObject, __p('code_objects/extra_file_object') autoload :MacroObject, __p('code_objects/macro_object') autoload :MethodObject, __p('code_objects/method_object') autoload :ModuleObject, __p('code_objects/module_object') autoload :NamespaceObject, __p('code_objects/namespace_object') autoload :Proxy, __p('code_objects/proxy') autoload :ProxyMethodError, __p('code_objects/proxy') autoload :RootObject, __p('code_objects/root_object') autoload :BUILTIN_ALL, __p('code_objects/base') autoload :BUILTIN_CLASSES, __p('code_objects/base') autoload :BUILTIN_MODULES, __p('code_objects/base') autoload :BUILTIN_EXCEPTIONS, __p('code_objects/base') autoload :CONSTANTMATCH, __p('code_objects/base') autoload :METHODMATCH, __p('code_objects/base') autoload :METHODNAMEMATCH, __p('code_objects/base') autoload :NAMESPACEMATCH, __p('code_objects/base') autoload :NSEP, __p('code_objects/base') autoload :NSEPQ, __p('code_objects/base') autoload :ISEP, __p('code_objects/base') autoload :ISEPQ, __p('code_objects/base') autoload :CSEP, __p('code_objects/base') autoload :CSEPQ, __p('code_objects/base') end # Handlers are called during the data processing part of YARD's # parsing phase. This allows YARD as well as any custom extension to # analyze source and generate {CodeObjects} to be stored for later use. module Handlers # CRuby Handlers # @since 0.8.0 module C autoload :Base, __p('handlers/c/base') autoload :AliasHandler, __p('handlers/c/alias_handler') autoload :AttributeHandler, __p('handlers/c/attribute_handler') autoload :ClassHandler, __p('handlers/c/class_handler') autoload :ConstantHandler, __p('handlers/c/constant_handler') autoload :HandlerMethods, __p('handlers/c/handler_methods') autoload :InitHandler, __p('handlers/c/init_handler') autoload :MethodHandler, __p('handlers/c/method_handler') autoload :MixinHandler, __p('handlers/c/mixin_handler') autoload :ModuleHandler, __p('handlers/c/module_handler') autoload :OverrideCommentHandler, __p('handlers/c/override_comment_handler') autoload :PathHandler, __p('handlers/c/path_handler') autoload :StructHandler, __p('handlers/c/struct_handler') autoload :SymbolHandler, __p('handlers/c/symbol_handler') end module Ruby # All Ruby handlers module Legacy # Handlers for old Ruby 1.8 parser autoload :Base, __p('handlers/ruby/legacy/base') autoload :AliasHandler, __p('handlers/ruby/legacy/alias_handler') autoload :AttributeHandler, __p('handlers/ruby/legacy/attribute_handler') autoload :ClassHandler, __p('handlers/ruby/legacy/class_handler') autoload :ClassConditionHandler, __p('handlers/ruby/legacy/class_condition_handler') autoload :ClassVariableHandler, __p('handlers/ruby/legacy/class_variable_handler') autoload :CommentHandler, __p('handlers/ruby/legacy/comment_handler') autoload :ConstantHandler, __p('handlers/ruby/legacy/constant_handler') autoload :DSLHandler, __p('handlers/ruby/legacy/dsl_handler') autoload :ExceptionHandler, __p('handlers/ruby/legacy/exception_handler') autoload :ExtendHandler, __p('handlers/ruby/legacy/extend_handler') autoload :MethodHandler, __p('handlers/ruby/legacy/method_handler') autoload :MixinHandler, __p('handlers/ruby/legacy/mixin_handler') autoload :ModuleHandler, __p('handlers/ruby/legacy/module_handler') autoload :ModuleFunctionHandler, __p('handlers/ruby/legacy/module_function_handler') autoload :PrivateConstantHandler, __p('handlers/ruby/legacy/private_constant_handler') autoload :VisibilityHandler, __p('handlers/ruby/legacy/visibility_handler') autoload :YieldHandler, __p('handlers/ruby/legacy/yield_handler') end autoload :Base, __p('handlers/ruby/base') autoload :AliasHandler, __p('handlers/ruby/alias_handler') autoload :AttributeHandler, __p('handlers/ruby/attribute_handler') autoload :ClassHandler, __p('handlers/ruby/class_handler') autoload :ClassConditionHandler, __p('handlers/ruby/class_condition_handler') autoload :ClassVariableHandler, __p('handlers/ruby/class_variable_handler') autoload :CommentHandler, __p('handlers/ruby/comment_handler') autoload :ConstantHandler, __p('handlers/ruby/constant_handler') autoload :DSLHandler, __p('handlers/ruby/dsl_handler') autoload :DSLHandlerMethods, __p('handlers/ruby/dsl_handler_methods') autoload :ExceptionHandler, __p('handlers/ruby/exception_handler') autoload :ExtendHandler, __p('handlers/ruby/extend_handler') autoload :MethodHandler, __p('handlers/ruby/method_handler') autoload :MethodConditionHandler, __p('handlers/ruby/method_condition_handler') autoload :MixinHandler, __p('handlers/ruby/mixin_handler') autoload :ModuleHandler, __p('handlers/ruby/module_handler') autoload :ModuleFunctionHandler, __p('handlers/ruby/module_function_handler') autoload :PrivateConstantHandler, __p('handlers/ruby/private_constant_handler') autoload :StructHandlerMethods, __p('handlers/ruby/struct_handler_methods') autoload :VisibilityHandler, __p('handlers/ruby/visibility_handler') autoload :YieldHandler, __p('handlers/ruby/yield_handler') end autoload :Base, __p('handlers/base') autoload :HandlerAborted, __p('handlers/base') autoload :NamespaceMissingError, __p('handlers/base') autoload :Processor, __p('handlers/processor') end # Namespace for internationalization (i18n) # @since 0.8.0 module I18n autoload :Locale, __p('i18n/locale') autoload :Message, __p('i18n/message') autoload :Messages, __p('i18n/messages') autoload :PotGenerator, __p('i18n/pot_generator') autoload :Text, __p('i18n/text') end # The parser namespace holds all parsing engines used by YARD. # Currently only Ruby and C (Ruby) parsers are implemented. module Parser module C # CRuby Parsing components autoload :BodyStatement, __p('parser/c/statement') autoload :Comment, __p('parser/c/statement') autoload :CommentParser, __p('parser/c/comment_parser') autoload :CParser, __p('parser/c/c_parser') autoload :Statement, __p('parser/c/statement') autoload :ToplevelStatement, __p('parser/c/statement') end module Ruby # Ruby parsing components. module Legacy # Handles Ruby parsing in Ruby 1.8. autoload :RipperParser, __p('parser/ruby/legacy/ruby_parser') autoload :RubyParser, __p('parser/ruby/legacy/ruby_parser') autoload :RubyToken, __p('parser/ruby/legacy/ruby_lex') autoload :Statement, __p('parser/ruby/legacy/statement') autoload :StatementList, __p('parser/ruby/legacy/statement_list') autoload :TokenList, __p('parser/ruby/legacy/token_list') end autoload :AstNode, __p('parser/ruby/ast_node') autoload :RubyParser, __p('parser/ruby/ruby_parser') end autoload :Base, __p('parser/base') autoload :ParserSyntaxError, __p('parser/source_parser') autoload :SourceParser, __p('parser/source_parser') autoload :UndocumentableError, __p('parser/source_parser') end module Rake # Holds Rake tasks used by YARD autoload :YardocTask, __p('rake/yardoc_task') end module Serializers # Namespace for components that serialize to various endpoints autoload :Base, __p('serializers/base') autoload :FileSystemSerializer, __p('serializers/file_system_serializer') autoload :ProcessSerializer, __p('serializers/process_serializer') autoload :StdoutSerializer, __p('serializers/stdout_serializer') autoload :YardocSerializer, __p('serializers/yardoc_serializer') end # Namespace for classes and modules that handle serving documentation over HTTP # # == Implementing a Custom Server # To customize the YARD server, see the {Adapter} and {Router} classes. # # == Rack Middleware # If you want to use the YARD server as a Rack middleware, see the documentation # in {RackMiddleware}. # # @since 0.6.0 module Server require __p('server') # Commands implement specific kinds of server responses which are routed # to by the {Router} class. To implement a custom command, subclass {Commands::Base}. module Commands autoload :Base, __p('server/commands/base') autoload :DisplayFileCommand, __p('server/commands/display_file_command') autoload :DisplayObjectCommand, __p('server/commands/display_object_command') autoload :FramesCommand, __p('server/commands/frames_command') autoload :ListCommand, __p('server/commands/list_command') autoload :LibraryCommand, __p('server/commands/library_command') autoload :LibraryIndexCommand, __p('server/commands/library_index_command') autoload :SearchCommand, __p('server/commands/search_command') autoload :StaticFileCommand, __p('server/commands/static_file_command') end autoload :Adapter, __p('server/adapter') autoload :DocServerSerializer, __p('server/doc_server_serializer') autoload :DocServerHelper, __p('server/doc_server_helper') autoload :FinishRequest, __p('server/adapter') autoload :LibraryVersion, __p('server/library_version') autoload :NotFoundError, __p('server/adapter') autoload :RackAdapter, __p('server/rack_adapter') autoload :RackMiddleware, __p('server/rack_adapter') autoload :Router, __p('server/router') autoload :StaticCaching, __p('server/static_caching') autoload :WebrickAdapter, __p('server/webrick_adapter') autoload :WebrickServlet, __p('server/webrick_adapter') end module Tags # Namespace for Tag components autoload :AttributeDirective, __p('tags/directives') autoload :DefaultFactory, __p('tags/default_factory') autoload :DefaultTag, __p('tags/default_tag') autoload :Directive, __p('tags/directives') autoload :EndGroupDirective, __p('tags/directives') autoload :GroupDirective, __p('tags/directives') autoload :Library, __p('tags/library') autoload :MacroDirective, __p('tags/directives') autoload :MethodDirective, __p('tags/directives') autoload :OptionTag, __p('tags/option_tag') autoload :OverloadTag, __p('tags/overload_tag') autoload :ParseDirective, __p('tags/directives') autoload :RefTag, __p('tags/ref_tag') autoload :RefTagList, __p('tags/ref_tag_list') autoload :ScopeDirective, __p('tags/directives') autoload :Tag, __p('tags/tag') autoload :TagFormatError, __p('tags/tag_format_error') autoload :VisibilityDirective, __p('tags/directives') end # Namespace for templating system module Templates module Helpers # Namespace for template helpers module Markup # Namespace for markup providers autoload :RDocMarkup, __p('templates/helpers/markup/rdoc_markup') autoload :RDocMarkdown, __p('templates/helpers/markup/rdoc_markdown') end autoload :BaseHelper, __p('templates/helpers/base_helper') autoload :FilterHelper, __p('templates/helpers/filter_helper') autoload :HtmlHelper, __p('templates/helpers/html_helper') autoload :HtmlSyntaxHighlightHelper, __p('templates/helpers/html_syntax_highlight_helper') autoload :MarkupHelper, __p('templates/helpers/markup_helper') autoload :MethodHelper, __p('templates/helpers/method_helper') autoload :ModuleHelper, __p('templates/helpers/module_helper') autoload :TextHelper, __p('templates/helpers/text_helper') autoload :UMLHelper, __p('templates/helpers/uml_helper') end autoload :Engine, __p('templates/engine') autoload :ErbCache, __p('templates/erb_cache') autoload :Section, __p('templates/section') autoload :Template, __p('templates/template') autoload :TemplateOptions, __p('templates/template_options') end autoload :Config, __p('config') autoload :Docstring, __p('docstring') autoload :DocstringParser, __p('docstring_parser') autoload :Logger, __p('logging') autoload :Options, __p('options') autoload :Registry, __p('registry') autoload :RegistryStore, __p('registry_store') autoload :StubProxy, __p('serializers/yardoc_serializer') autoload :Verifier, __p('verifier') end undef __p yard-0.8.7.3/lib/yard.rb0000644000004100000410000000421512261240652014712 0ustar www-datawww-datarequire File.expand_path('../yard/version.rb', __FILE__) module YARD # The root path for YARD source libraries ROOT = File.expand_path(File.dirname(__FILE__)) # The root path for YARD builtin templates TEMPLATE_ROOT = File.join(ROOT, '..', 'templates') # @deprecated Use {Config::CONFIG_DIR} CONFIG_DIR = File.expand_path('~/.yard') # An alias to {Parser::SourceParser}'s parsing method # # @example Parse a glob of files # YARD.parse('lib/**/*.rb') # @see Parser::SourceParser.parse def self.parse(*args) Parser::SourceParser.parse(*args) end # An alias to {Parser::SourceParser}'s parsing method # # @example Parse a string of input # YARD.parse_string('class Foo; end') # @see Parser::SourceParser.parse_string def self.parse_string(*args) Parser::SourceParser.parse_string(*args) end # (see YARD::Config.load_plugins) # @deprecated Use {Config.load_plugins} def self.load_plugins; YARD::Config.load_plugins end # @return [Boolean] whether YARD is being run inside of Windows def self.windows? return @windows if defined? @windows require 'rbconfig' if ::RbConfig::CONFIG['host_os'] =~ /mingw|win32|cygwin/ @wnidows = true else @windows = false end ensure @windows ||= false end # @return [Boolean] whether YARD is being run in Ruby 1.8 mode def self.ruby18?; !ruby19? end # @return [Boolean] whether YARD is being run in Ruby 1.9 mode def self.ruby19?; @ruby19 ||= (RUBY_VERSION >= "1.9.1") end # @return [Boolean] whether YARD is being run in Ruby 2.0 def self.ruby2?; @ruby2 ||= (RUBY_VERSION >= '2.0.0') end end # Keep track of Ruby version for compatibility code # @deprecated Use {YARD.ruby18?} or {YARD.ruby19?} instead. RUBY18, RUBY19 = YARD.ruby18?, YARD.ruby19? # Load Ruby core extension classes Dir.glob(File.join(YARD::ROOT, 'yard', 'core_ext', '*.rb')).each do |file| require file end # Backport RubyGems SourceIndex and other classes require File.join(YARD::ROOT, 'yard', 'rubygems', 'backports') ['autoload', 'globals'].each do |file| require File.join(YARD::ROOT, 'yard', file) end # Load YARD configuration options (and plugins) YARD::Config.load yard-0.8.7.3/metadata.yml0000644000004100000410000005553412261240652015175 0ustar www-datawww-data--- !ruby/object:Gem::Specification name: yard version: !ruby/object:Gem::Version version: 0.8.7.3 platform: ruby authors: - Loren Segal autorequire: bindir: bin cert_chain: [] date: 2013-11-01 00:00:00.000000000 Z dependencies: [] description: |2 YARD is a documentation generation tool for the Ruby programming language. It enables the user to generate consistent, usable documentation that can be exported to a number of formats very easily, and also supports extending for custom Ruby constructs such as custom class level definitions. email: lsegal@soen.ca executables: - yard - yardoc - yri extensions: [] extra_rdoc_files: [] files: - docs/CodeObjects.md - docs/GettingStarted.md - docs/Handlers.md - docs/images/code-objects-class-diagram.png - docs/images/handlers-class-diagram.png - docs/images/overview-class-diagram.png - docs/images/parser-class-diagram.png - docs/images/tags-class-diagram.png - docs/Overview.md - docs/Parser.md - docs/Tags.md - docs/TagsArch.md - docs/templates/default/fulldoc/html/full_list_tag.erb - docs/templates/default/fulldoc/html/setup.rb - docs/templates/default/layout/html/setup.rb - docs/templates/default/layout/html/tag_list.erb - docs/templates/default/yard_tags/html/list.erb - docs/templates/default/yard_tags/html/setup.rb - docs/templates/plugin.rb - docs/Templates.md - docs/WhatsNew.md - bin/yard - bin/yardoc - bin/yri - lib/rubygems_plugin.rb - lib/yard/autoload.rb - lib/yard/cli/command.rb - lib/yard/cli/command_parser.rb - lib/yard/cli/config.rb - lib/yard/cli/diff.rb - lib/yard/cli/display.rb - lib/yard/cli/gems.rb - lib/yard/cli/graph.rb - lib/yard/cli/help.rb - lib/yard/cli/i18n.rb - lib/yard/cli/list.rb - lib/yard/cli/markup_types.rb - lib/yard/cli/server.rb - lib/yard/cli/stats.rb - lib/yard/cli/yardoc.rb - lib/yard/cli/yardopts_command.rb - lib/yard/cli/yri.rb - lib/yard/code_objects/base.rb - lib/yard/code_objects/class_object.rb - lib/yard/code_objects/class_variable_object.rb - lib/yard/code_objects/constant_object.rb - lib/yard/code_objects/extended_method_object.rb - lib/yard/code_objects/extra_file_object.rb - lib/yard/code_objects/macro_object.rb - lib/yard/code_objects/method_object.rb - lib/yard/code_objects/module_object.rb - lib/yard/code_objects/namespace_object.rb - lib/yard/code_objects/proxy.rb - lib/yard/code_objects/root_object.rb - lib/yard/config.rb - lib/yard/core_ext/array.rb - lib/yard/core_ext/file.rb - lib/yard/core_ext/hash.rb - lib/yard/core_ext/insertion.rb - lib/yard/core_ext/module.rb - lib/yard/core_ext/string.rb - lib/yard/core_ext/symbol_hash.rb - lib/yard/docstring.rb - lib/yard/docstring_parser.rb - lib/yard/globals.rb - lib/yard/handlers/base.rb - lib/yard/handlers/c/alias_handler.rb - lib/yard/handlers/c/attribute_handler.rb - lib/yard/handlers/c/base.rb - lib/yard/handlers/c/class_handler.rb - lib/yard/handlers/c/constant_handler.rb - lib/yard/handlers/c/handler_methods.rb - lib/yard/handlers/c/init_handler.rb - lib/yard/handlers/c/method_handler.rb - lib/yard/handlers/c/mixin_handler.rb - lib/yard/handlers/c/module_handler.rb - lib/yard/handlers/c/override_comment_handler.rb - lib/yard/handlers/c/path_handler.rb - lib/yard/handlers/c/struct_handler.rb - lib/yard/handlers/c/symbol_handler.rb - lib/yard/handlers/processor.rb - lib/yard/handlers/ruby/alias_handler.rb - lib/yard/handlers/ruby/attribute_handler.rb - lib/yard/handlers/ruby/base.rb - lib/yard/handlers/ruby/class_condition_handler.rb - lib/yard/handlers/ruby/class_handler.rb - lib/yard/handlers/ruby/class_variable_handler.rb - lib/yard/handlers/ruby/comment_handler.rb - lib/yard/handlers/ruby/constant_handler.rb - lib/yard/handlers/ruby/dsl_handler.rb - lib/yard/handlers/ruby/dsl_handler_methods.rb - lib/yard/handlers/ruby/exception_handler.rb - lib/yard/handlers/ruby/extend_handler.rb - lib/yard/handlers/ruby/legacy/alias_handler.rb - lib/yard/handlers/ruby/legacy/attribute_handler.rb - lib/yard/handlers/ruby/legacy/base.rb - lib/yard/handlers/ruby/legacy/class_condition_handler.rb - lib/yard/handlers/ruby/legacy/class_handler.rb - lib/yard/handlers/ruby/legacy/class_variable_handler.rb - lib/yard/handlers/ruby/legacy/comment_handler.rb - lib/yard/handlers/ruby/legacy/constant_handler.rb - lib/yard/handlers/ruby/legacy/dsl_handler.rb - lib/yard/handlers/ruby/legacy/exception_handler.rb - lib/yard/handlers/ruby/legacy/extend_handler.rb - lib/yard/handlers/ruby/legacy/method_handler.rb - lib/yard/handlers/ruby/legacy/mixin_handler.rb - lib/yard/handlers/ruby/legacy/module_function_handler.rb - lib/yard/handlers/ruby/legacy/module_handler.rb - lib/yard/handlers/ruby/legacy/private_constant_handler.rb - lib/yard/handlers/ruby/legacy/visibility_handler.rb - lib/yard/handlers/ruby/legacy/yield_handler.rb - lib/yard/handlers/ruby/method_condition_handler.rb - lib/yard/handlers/ruby/method_handler.rb - lib/yard/handlers/ruby/mixin_handler.rb - lib/yard/handlers/ruby/module_function_handler.rb - lib/yard/handlers/ruby/module_handler.rb - lib/yard/handlers/ruby/private_constant_handler.rb - lib/yard/handlers/ruby/struct_handler_methods.rb - lib/yard/handlers/ruby/visibility_handler.rb - lib/yard/handlers/ruby/yield_handler.rb - lib/yard/i18n/locale.rb - lib/yard/i18n/message.rb - lib/yard/i18n/messages.rb - lib/yard/i18n/po_parser.rb - lib/yard/i18n/pot_generator.rb - lib/yard/i18n/text.rb - lib/yard/logging.rb - lib/yard/options.rb - lib/yard/parser/base.rb - lib/yard/parser/c/c_parser.rb - lib/yard/parser/c/comment_parser.rb - lib/yard/parser/c/statement.rb - lib/yard/parser/ruby/ast_node.rb - lib/yard/parser/ruby/legacy/ruby_lex.rb - lib/yard/parser/ruby/legacy/ruby_parser.rb - lib/yard/parser/ruby/legacy/statement.rb - lib/yard/parser/ruby/legacy/statement_list.rb - lib/yard/parser/ruby/legacy/token_list.rb - lib/yard/parser/ruby/ruby_parser.rb - lib/yard/parser/source_parser.rb - lib/yard/rake/yardoc_task.rb - lib/yard/registry.rb - lib/yard/registry_store.rb - lib/yard/rubygems/backports/gem.rb - lib/yard/rubygems/backports/LICENSE.txt - lib/yard/rubygems/backports/MIT.txt - lib/yard/rubygems/backports/source_index.rb - lib/yard/rubygems/backports.rb - lib/yard/rubygems/doc_manager.rb - lib/yard/rubygems/specification.rb - lib/yard/serializers/base.rb - lib/yard/serializers/file_system_serializer.rb - lib/yard/serializers/process_serializer.rb - lib/yard/serializers/stdout_serializer.rb - lib/yard/serializers/yardoc_serializer.rb - lib/yard/server/adapter.rb - lib/yard/server/commands/base.rb - lib/yard/server/commands/display_file_command.rb - lib/yard/server/commands/display_object_command.rb - lib/yard/server/commands/frames_command.rb - lib/yard/server/commands/library_command.rb - lib/yard/server/commands/library_index_command.rb - lib/yard/server/commands/list_command.rb - lib/yard/server/commands/search_command.rb - lib/yard/server/commands/static_file_command.rb - lib/yard/server/doc_server_helper.rb - lib/yard/server/doc_server_serializer.rb - lib/yard/server/library_version.rb - lib/yard/server/rack_adapter.rb - lib/yard/server/router.rb - lib/yard/server/static_caching.rb - lib/yard/server/templates/default/fulldoc/html/css/custom.css - lib/yard/server/templates/default/fulldoc/html/images/processing.gif - lib/yard/server/templates/default/fulldoc/html/js/autocomplete.js - lib/yard/server/templates/default/layout/html/breadcrumb.erb - lib/yard/server/templates/default/layout/html/script_setup.erb - lib/yard/server/templates/default/layout/html/setup.rb - lib/yard/server/templates/default/method_details/html/permalink.erb - lib/yard/server/templates/default/method_details/html/setup.rb - lib/yard/server/templates/doc_server/library_list/html/contents.erb - lib/yard/server/templates/doc_server/library_list/html/headers.erb - lib/yard/server/templates/doc_server/library_list/html/library_list.erb - lib/yard/server/templates/doc_server/library_list/html/setup.rb - lib/yard/server/templates/doc_server/library_list/html/title.erb - lib/yard/server/templates/doc_server/processing/html/processing.erb - lib/yard/server/templates/doc_server/processing/html/setup.rb - lib/yard/server/templates/doc_server/search/html/search.erb - lib/yard/server/templates/doc_server/search/html/setup.rb - lib/yard/server/webrick_adapter.rb - lib/yard/server.rb - lib/yard/tags/default_factory.rb - lib/yard/tags/default_tag.rb - lib/yard/tags/directives.rb - lib/yard/tags/library.rb - lib/yard/tags/option_tag.rb - lib/yard/tags/overload_tag.rb - lib/yard/tags/ref_tag.rb - lib/yard/tags/ref_tag_list.rb - lib/yard/tags/tag.rb - lib/yard/tags/tag_format_error.rb - lib/yard/templates/engine.rb - lib/yard/templates/erb_cache.rb - lib/yard/templates/helpers/base_helper.rb - lib/yard/templates/helpers/filter_helper.rb - lib/yard/templates/helpers/html_helper.rb - lib/yard/templates/helpers/html_syntax_highlight_helper.rb - lib/yard/templates/helpers/markup/rdoc_markdown.rb - lib/yard/templates/helpers/markup/rdoc_markup.rb - lib/yard/templates/helpers/markup_helper.rb - lib/yard/templates/helpers/method_helper.rb - lib/yard/templates/helpers/module_helper.rb - lib/yard/templates/helpers/text_helper.rb - lib/yard/templates/helpers/uml_helper.rb - lib/yard/templates/section.rb - lib/yard/templates/template.rb - lib/yard/templates/template_options.rb - lib/yard/verifier.rb - lib/yard/version.rb - lib/yard.rb - spec/cli/command_parser_spec.rb - spec/cli/command_spec.rb - spec/cli/config_spec.rb - spec/cli/diff_spec.rb - spec/cli/display_spec.rb - spec/cli/gems_spec.rb - spec/cli/graph_spec.rb - spec/cli/help_spec.rb - spec/cli/i18n_spec.rb - spec/cli/list_spec.rb - spec/cli/markup_types_spec.rb - spec/cli/server_spec.rb - spec/cli/stats_spec.rb - spec/cli/yardoc_spec.rb - spec/cli/yri_spec.rb - spec/code_objects/base_spec.rb - spec/code_objects/class_object_spec.rb - spec/code_objects/code_object_list_spec.rb - spec/code_objects/constants_spec.rb - spec/code_objects/extra_file_object_spec.rb - spec/code_objects/macro_object_spec.rb - spec/code_objects/method_object_spec.rb - spec/code_objects/module_object_spec.rb - spec/code_objects/namespace_object_spec.rb - spec/code_objects/proxy_spec.rb - spec/code_objects/spec_helper.rb - spec/config_spec.rb - spec/core_ext/array_spec.rb - spec/core_ext/file_spec.rb - spec/core_ext/hash_spec.rb - spec/core_ext/insertion_spec.rb - spec/core_ext/module_spec.rb - spec/core_ext/string_spec.rb - spec/core_ext/symbol_hash_spec.rb - spec/docstring_parser_spec.rb - spec/docstring_spec.rb - spec/handlers/alias_handler_spec.rb - spec/handlers/attribute_handler_spec.rb - spec/handlers/base_spec.rb - spec/handlers/c/alias_handler_spec.rb - spec/handlers/c/attribute_handler_spec.rb - spec/handlers/c/class_handler_spec.rb - spec/handlers/c/constant_handler_spec.rb - spec/handlers/c/init_handler_spec.rb - spec/handlers/c/method_handler_spec.rb - spec/handlers/c/mixin_handler_spec.rb - spec/handlers/c/module_handler_spec.rb - spec/handlers/c/override_comment_handler_spec.rb - spec/handlers/c/path_handler_spec.rb - spec/handlers/c/spec_helper.rb - spec/handlers/c/struct_handler_spec.rb - spec/handlers/class_condition_handler_spec.rb - spec/handlers/class_handler_spec.rb - spec/handlers/class_variable_handler_spec.rb - spec/handlers/constant_handler_spec.rb - spec/handlers/dsl_handler_spec.rb - spec/handlers/examples/alias_handler_001.rb.txt - spec/handlers/examples/attribute_handler_001.rb.txt - spec/handlers/examples/class_condition_handler_001.rb.txt - spec/handlers/examples/class_handler_001.rb.txt - spec/handlers/examples/class_variable_handler_001.rb.txt - spec/handlers/examples/constant_handler_001.rb.txt - spec/handlers/examples/dsl_handler_001.rb.txt - spec/handlers/examples/exception_handler_001.rb.txt - spec/handlers/examples/extend_handler_001.rb.txt - spec/handlers/examples/method_condition_handler_001.rb.txt - spec/handlers/examples/method_handler_001.rb.txt - spec/handlers/examples/mixin_handler_001.rb.txt - spec/handlers/examples/module_handler_001.rb.txt - spec/handlers/examples/private_constant_handler_001.rb.txt - spec/handlers/examples/process_handler_001.rb.txt - spec/handlers/examples/visibility_handler_001.rb.txt - spec/handlers/examples/yield_handler_001.rb.txt - spec/handlers/exception_handler_spec.rb - spec/handlers/extend_handler_spec.rb - spec/handlers/legacy_base_spec.rb - spec/handlers/method_condition_handler_spec.rb - spec/handlers/method_handler_spec.rb - spec/handlers/mixin_handler_spec.rb - spec/handlers/module_function_handler_spec.rb - spec/handlers/module_handler_spec.rb - spec/handlers/private_constant_handler_spec.rb - spec/handlers/processor_spec.rb - spec/handlers/ruby/base_spec.rb - spec/handlers/ruby/legacy/base_spec.rb - spec/handlers/spec_helper.rb - spec/handlers/visibility_handler_spec.rb - spec/handlers/yield_handler_spec.rb - spec/i18n/locale_spec.rb - spec/i18n/message_spec.rb - spec/i18n/messages_spec.rb - spec/i18n/pot_generator_spec.rb - spec/i18n/text_spec.rb - spec/logging_spec.rb - spec/options_spec.rb - spec/parser/base_spec.rb - spec/parser/c_parser_spec.rb - spec/parser/examples/array.c.txt - spec/parser/examples/example1.rb.txt - spec/parser/examples/extrafile.c.txt - spec/parser/examples/multifile.c.txt - spec/parser/examples/override.c.txt - spec/parser/examples/parse_in_order_001.rb.txt - spec/parser/examples/parse_in_order_002.rb.txt - spec/parser/examples/tag_handler_001.rb.txt - spec/parser/ruby/ast_node_spec.rb - spec/parser/ruby/legacy/statement_list_spec.rb - spec/parser/ruby/legacy/token_list_spec.rb - spec/parser/ruby/ruby_parser_spec.rb - spec/parser/source_parser_spec.rb - spec/parser/tag_parsing_spec.rb - spec/rake/yardoc_task_spec.rb - spec/registry_spec.rb - spec/registry_store_spec.rb - spec/rubygems/doc_manager_spec.rb - spec/serializers/data/serialized_yardoc/checksums - spec/serializers/data/serialized_yardoc/objects/Foo/bar_i.dat - spec/serializers/data/serialized_yardoc/objects/Foo/baz_i.dat - spec/serializers/data/serialized_yardoc/objects/Foo.dat - spec/serializers/data/serialized_yardoc/objects/root.dat - spec/serializers/data/serialized_yardoc/proxy_types - spec/serializers/file_system_serializer_spec.rb - spec/serializers/spec_helper.rb - spec/serializers/yardoc_serializer_spec.rb - spec/server/adapter_spec.rb - spec/server/commands/base_spec.rb - spec/server/commands/library_command_spec.rb - spec/server/commands/static_file_command_spec.rb - spec/server/doc_server_helper_spec.rb - spec/server/doc_server_serializer_spec.rb - spec/server/rack_adapter_spec.rb - spec/server/router_spec.rb - spec/server/spec_helper.rb - spec/server/static_caching_spec.rb - spec/server/webrick_servlet_spec.rb - spec/server_spec.rb - spec/spec_helper.rb - spec/tags/default_factory_spec.rb - spec/tags/default_tag_spec.rb - spec/tags/directives_spec.rb - spec/tags/library_spec.rb - spec/tags/overload_tag_spec.rb - spec/tags/ref_tag_list_spec.rb - spec/templates/class_spec.rb - spec/templates/constant_spec.rb - spec/templates/engine_spec.rb - spec/templates/examples/class001.html - spec/templates/examples/class001.txt - spec/templates/examples/class002.html - spec/templates/examples/constant001.txt - spec/templates/examples/constant002.txt - spec/templates/examples/constant003.txt - spec/templates/examples/method001.html - spec/templates/examples/method001.txt - spec/templates/examples/method002.html - spec/templates/examples/method002.txt - spec/templates/examples/method003.html - spec/templates/examples/method003.txt - spec/templates/examples/method004.html - spec/templates/examples/method004.txt - spec/templates/examples/method005.html - spec/templates/examples/method005.txt - spec/templates/examples/module001.dot - spec/templates/examples/module001.html - spec/templates/examples/module001.txt - spec/templates/examples/module002.html - spec/templates/examples/module003.html - spec/templates/examples/module004.html - spec/templates/examples/tag001.txt - spec/templates/helpers/base_helper_spec.rb - spec/templates/helpers/html_helper_spec.rb - spec/templates/helpers/html_syntax_highlight_helper_spec.rb - spec/templates/helpers/markup/rdoc_markup_spec.rb - spec/templates/helpers/markup_helper_spec.rb - spec/templates/helpers/method_helper_spec.rb - spec/templates/helpers/shared_signature_examples.rb - spec/templates/helpers/text_helper_spec.rb - spec/templates/method_spec.rb - spec/templates/module_spec.rb - spec/templates/onefile_spec.rb - spec/templates/section_spec.rb - spec/templates/spec_helper.rb - spec/templates/tag_spec.rb - spec/templates/template_spec.rb - spec/verifier_spec.rb - templates/default/class/dot/setup.rb - templates/default/class/dot/superklass.erb - templates/default/class/html/constructor_details.erb - templates/default/class/html/setup.rb - templates/default/class/html/subclasses.erb - templates/default/class/setup.rb - templates/default/class/text/setup.rb - templates/default/class/text/subclasses.erb - templates/default/constant/text/header.erb - templates/default/constant/text/setup.rb - templates/default/docstring/html/abstract.erb - templates/default/docstring/html/deprecated.erb - templates/default/docstring/html/index.erb - templates/default/docstring/html/note.erb - templates/default/docstring/html/private.erb - templates/default/docstring/html/returns_void.erb - templates/default/docstring/html/text.erb - templates/default/docstring/html/todo.erb - templates/default/docstring/setup.rb - templates/default/docstring/text/abstract.erb - templates/default/docstring/text/deprecated.erb - templates/default/docstring/text/index.erb - templates/default/docstring/text/note.erb - templates/default/docstring/text/private.erb - templates/default/docstring/text/returns_void.erb - templates/default/docstring/text/text.erb - templates/default/docstring/text/todo.erb - templates/default/fulldoc/html/css/common.css - templates/default/fulldoc/html/css/full_list.css - templates/default/fulldoc/html/css/style.css - templates/default/fulldoc/html/frames.erb - templates/default/fulldoc/html/full_list.erb - templates/default/fulldoc/html/full_list_class.erb - templates/default/fulldoc/html/full_list_file.erb - templates/default/fulldoc/html/full_list_method.erb - templates/default/fulldoc/html/js/app.js - templates/default/fulldoc/html/js/full_list.js - templates/default/fulldoc/html/js/jquery.js - templates/default/fulldoc/html/setup.rb - templates/default/layout/dot/header.erb - templates/default/layout/dot/setup.rb - templates/default/layout/html/breadcrumb.erb - templates/default/layout/html/files.erb - templates/default/layout/html/footer.erb - templates/default/layout/html/headers.erb - templates/default/layout/html/index.erb - templates/default/layout/html/layout.erb - templates/default/layout/html/listing.erb - templates/default/layout/html/objects.erb - templates/default/layout/html/script_setup.erb - templates/default/layout/html/search.erb - templates/default/layout/html/setup.rb - templates/default/method/html/header.erb - templates/default/method/setup.rb - templates/default/method/text/header.erb - templates/default/method_details/html/header.erb - templates/default/method_details/html/method_signature.erb - templates/default/method_details/html/source.erb - templates/default/method_details/setup.rb - templates/default/method_details/text/header.erb - templates/default/method_details/text/method_signature.erb - templates/default/method_details/text/setup.rb - templates/default/module/dot/child.erb - templates/default/module/dot/dependencies.erb - templates/default/module/dot/header.erb - templates/default/module/dot/info.erb - templates/default/module/dot/setup.rb - templates/default/module/html/attribute_details.erb - templates/default/module/html/attribute_summary.erb - templates/default/module/html/box_info.erb - templates/default/module/html/children.erb - templates/default/module/html/constant_summary.erb - templates/default/module/html/defines.erb - templates/default/module/html/header.erb - templates/default/module/html/inherited_attributes.erb - templates/default/module/html/inherited_constants.erb - templates/default/module/html/inherited_methods.erb - templates/default/module/html/item_summary.erb - templates/default/module/html/method_details_list.erb - templates/default/module/html/method_summary.erb - templates/default/module/html/methodmissing.erb - templates/default/module/html/pre_docstring.erb - templates/default/module/setup.rb - templates/default/module/text/children.erb - templates/default/module/text/class_meths_list.erb - templates/default/module/text/extends.erb - templates/default/module/text/header.erb - templates/default/module/text/includes.erb - templates/default/module/text/instance_meths_list.erb - templates/default/module/text/setup.rb - templates/default/onefile/html/files.erb - templates/default/onefile/html/headers.erb - templates/default/onefile/html/layout.erb - templates/default/onefile/html/readme.erb - templates/default/onefile/html/setup.rb - templates/default/root/dot/child.erb - templates/default/root/dot/setup.rb - templates/default/root/html/setup.rb - templates/default/tags/html/example.erb - templates/default/tags/html/index.erb - templates/default/tags/html/option.erb - templates/default/tags/html/overload.erb - templates/default/tags/html/see.erb - templates/default/tags/html/tag.erb - templates/default/tags/setup.rb - templates/default/tags/text/example.erb - templates/default/tags/text/index.erb - templates/default/tags/text/option.erb - templates/default/tags/text/overload.erb - templates/default/tags/text/see.erb - templates/default/tags/text/tag.erb - templates/guide/class/html/setup.rb - templates/guide/docstring/html/setup.rb - templates/guide/fulldoc/html/css/style.css - templates/guide/fulldoc/html/js/app.js - templates/guide/fulldoc/html/setup.rb - templates/guide/layout/html/layout.erb - templates/guide/layout/html/setup.rb - templates/guide/method/html/header.erb - templates/guide/method/html/setup.rb - templates/guide/module/html/header.erb - templates/guide/module/html/method_list.erb - templates/guide/module/html/setup.rb - templates/guide/onefile/html/files.erb - templates/guide/onefile/html/setup.rb - templates/guide/onefile/html/toc.erb - templates/guide/tags/html/setup.rb - benchmarks/builtins_vs_eval.rb - benchmarks/concat_vs_join.rb - benchmarks/erb_vs_erubis.rb - benchmarks/format_args.rb - benchmarks/generation.rb - benchmarks/marshal_vs_dbm.rb - benchmarks/parsing.rb - benchmarks/pathname_vs_string.rb - benchmarks/rdoc_vs_yardoc.rb - benchmarks/registry_store_types.rb - benchmarks/ri_vs_yri.rb - benchmarks/ripper_parser.rb - benchmarks/splat_vs_flatten.rb - benchmarks/template_erb.rb - benchmarks/template_format.rb - benchmarks/template_profile.rb - benchmarks/yri_cache.rb - LICENSE - LEGAL - README.md - Rakefile - .yardopts - yard.gemspec homepage: http://yardoc.org licenses: - MIT metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - '>=' - !ruby/object:Gem::Version version: '0' requirements: [] rubyforge_project: yard rubygems_version: 2.0.3 signing_key: specification_version: 4 summary: Documentation tool for consistent and usable documentation in Ruby. test_files: [] has_rdoc: yard yard-0.8.7.3/docs/0000755000004100000410000000000012261240652013606 5ustar www-datawww-datayard-0.8.7.3/docs/CodeObjects.md0000644000004100000410000001310012261240652016307 0ustar www-datawww-data# @title CodeObjects Architecture # CodeObjects Architecture Code objects are Ruby objects that describe the code being documented. For instance, all classes, modules, methods, etc. are all extracted from the Ruby source as code objects. All of these code objects extend from the {YARD::CodeObjects::Base} class, which provides basic attributes like source location, source code, name and path. ## CodeObjects Organization Code objects are divided into two basic types. {YARD::CodeObjects::NamespaceObject NamespaceObjects} and non-namespace objects. A namespace object refers to any object in Ruby that can have other objects defined inside of it. In the context of Ruby, this specifically means modules and classes (both of which are subclasses of `NamespaceObject`). These objects act like tree structures, maintaining a list of all of their direct children. All non namespace objects are simply subclasses of the Base class. The {YARD::CodeObjects::RootObject RootObject} is a special kind of `NamespaceObject` which refers to the top level namespace in Ruby. Methods that accept a namespace object as a parameter should also accept the symbol `:root` as a shortcut for the root object. The following is an overview of the classes within the `CodeObjects` namespace: ![CodeObjects Class Diagram](images/code-objects-class-diagram.png) ## Unique Path Representation All CodeObjects are uniquely defined by their implementation of {YARD::CodeObjects::Base#path}. This path is used to locate or store a code object in the {YARD::Registry}. It is therefore essential that any Base subclass return a unique String value for #path so that the object may co-exist with other objects in the Registry. In practice, a path is simply the conventional Ruby representation of a class, module, constant, class variable or method. For example, the following objects would have the following respective paths: * Class `Klass` inside module `Mod`: `Mod::Klass` * Instance method `bar` inside class `Foo`: `Foo#bar` * Class method `bar` inside class `Foo`: `Foo.bar` * Constant `VERSION` inside class `YARD`: `YARD::VERSION` * Class variable `@@abc` inside class `A`: `A::@@abc` ## Registry CodeObjects classes are coupled with the {YARD::Registry} class which keeps track of all instantiated code objects. This is an explicit design choice to allow objects to be fetched, cached, imported and exported from a centralized location. As mentioned above, this coupling is a result of the fact that each object is uniquely identified by its path, which is used to implement lookups. You can read more about the registry in the {YARD::Registry} class. ## Identity Map Code objects are instantiated using an identity-map like implementation that guarantees only one unique Ruby object exists for an object described by a specific path. This allows developers to create a code object without checking if it already exists in the {YARD::Registry}. The following example will only create one object: id = ClassObject.new(:root, "MyClass").object_id #=> 13352 ClassObject.new(:root, "MyClass").object_id #=> 13352 ## Proxy Objects In addition to providing access to existing objects, a {YARD::CodeObjects::Proxy} class exists which can represent an object at a path that may or may not have been created. This is necessary to represent a reference to an object in code that is never defined in the same body of source code, or perhaps defined later. If any attributes of a proxy are accessed, it will immediately be resolved to the object at its declared path. In the case where such an object exists, it will act as a delegate to the object. However, if the object does not exist, a warning will be raised. Whenever arbitrary code objects are used, care should be taken in order to make sure attributes are not accessed on unresolvable proxies. An unresolvable proxy will return a class name of `Proxy` and #type of `:proxy`, for example: P(:InvalidObject).type == :proxy #=> true P(:InvalidObject).is_a?(Proxy) #=> true ## Adding Data to Code Objects Code objects act as hash-like structures that allow any arbitrary value to be set. This allows easy extending of existing objects without creating custom subclasses. For instance, to add a timestamp to a method object (when it was modified, maybe), it is possible to simply do: object = MethodObject.new(:root, "my_method") object[:modified_at] = Time.now This value can now be retrieved on this object both by the hash `[]` syntax as well as like any other method: object.modified_at #=> 2009-06-03 20:08:46 -0400 ## Creating a Custom CodeObject It should first be mentioned that creating a custom code object should not be necessary in most cases, except when functionality that cannot be represented by classical Ruby objects is added. A good example *might* be a test class, which although is technically a Ruby class, has a significantly different purpose in documentation and needs a different set of metadata, as well as its own representation in documentation. The {YARD::CodeObjects::Base#path} implementation is the most important part of the code object architecture. The first thing any custom code object must guarantee is that its path value is unique among all other objects. The recommended way to do this with custom objects is to add a descriptive prefix to the path. For example, the following is an implementation of the path for a hypothetical `FooObject`: def path "__FooPrefix" + sep + super end Note that if our FooObject is a `NamespaceObject`, meaning if it can have child FooObjects defined inside of it, you may need to verify that the prefix is only applied once. yard-0.8.7.3/docs/Templates.md0000644000004100000410000004537312261240652016102 0ustar www-datawww-data# @title Templates Architecture # Templates Architecture Templates are the main component in the output rendering process of YARD, which is invoked when conventional HTML/text output needs to be rendered for a set of code objects. ## Design Goals The general design attempts to be as abstracted from actual content and templates as possible. Unlike RDoc which uses one file to describe the entire template, YARD splits up the rendering of code objects into small components, allowing template modification for smaller subsets of a full template without having to duplicate the entire template itself. This is necessary because of YARD's support for plugins. YARD is designed for extensibility by external plugins, and because of this, no one plugin can be responsible for the entire template because no one plugin knows about the other plugins being used. For instance, if an RSpec plugin was added to support and document specifications in class templates, this information would need to be transparently added to the template to work in conjunction with any other plugin that performed similar template modifications. The design goals can be summarized as follows: 1. Output should be able to be rendered for any arbitrary format with little modification to YARD's source code. The addition of extra templates should be sufficient. 2. The output rendered for an object should independently rendered data from arbitrary sources. These independent components are called "sections". 3. Sections should be able to be inserted into any object without affecting any existing sections in the document. This allows for easy modification of templates by plugins. ## Templates Template modules are the objects used to orchestrate the design goals listed above. Specifically, they organize the sections and render the template contents depending on the format. ## Engine The Engine class orchestrates the creation and rendering of Template modules and handles serialization or specific rendering scenarios (like HTML). To create a template, use the {YARD::Templates::Engine.template template} method. The two most common methods used to initiate output are the {YARD::Templates::Engine.render render} and {YARD::Templates::Engine.generate generate} methods which generate and optionally serialize output to a file. The latter, `#generate`, is used specially to generate HTML documentation and copy over assets that may be needed. For instance, an object may be rendered with: YARD::Templates::Engine.render(:object => myobject) A set of objects may be rendered into HTML documentation by using: # all_objects is an array of module and class objects # options includes a :serializer key to copy output to the file system YARD::Templates::Engine.generate(all_objects, options) Note that these methods should not be called directly. The {YARD::CodeObjects::Base} class has a {YARD::CodeObjects::Base#format #format} helper method to render an object. For instance, the above render example is equivalent to the simple call `myobject.format`. The `generate` method is a special kind of render and is called from the {YARD::CLI::Yardoc} command line utility. ## Template Options A template keeps state when it is rendering output. This state is kept in an options hash which is initially passed to it during instantiation. Some default options set the template style (`:template`), the output format (`:format`), and the serializer to use (`:serializer`). This options hash is modifiable from all methods seen above. For example, initializing a template to output as HTML instead of text can be done as follows: myobject.format(:format => :html) ## Serializer This class abstracts the logic involved in deciding how to serialize data to the expected endpoint. For instance, there is both a {YARD::Serializers::StdoutSerializer StdoutSerializer} and {YARD::Serializers::FileSystemSerializer FileSystemSerializer} class for outputting to console or to a file respectively. When endpoints with locations are used (like files or URLs), the serializer implements the {YARD::Serializers::Base#serialized_path #serialized_path} method. This allows the translation from a code object to its path at the endpoint, which enables inter-document linking. Rendered objects are automatically serialized using the object if present, otherwise the rendered object is returned as a string to its parent. Nested Templates automatically set the serializer to nil so that they return as a String to their parent. ## Creating a Template Templates are represented by a directory inside the {YARD::Templates::Engine.template_paths} on disk. A standard template directory looks like the following tree: (Assuming templates/ is a template path) templates `-- default |-- class | |-- dot | | |-- setup.rb | | `-- superklass.erb | |-- html | | |-- constructor_details.erb | | |-- setup.rb | | `-- subclasses.erb | |-- setup.rb | `-- text | |-- setup.rb | `-- subclasses.erb |-- docstring | |-- html | | |-- abstract.erb | | |-- deprecated.erb | | |-- index.erb | | `-- text.erb | |-- setup.rb | `-- text | |-- abstract.erb | |-- deprecated.erb | |-- index.erb | `-- text.erb The path `default` refers to the template style (:template key in options hash) and the directories at the next level (such as `class`) refer to template `:type` (options hash key) for a template. The next directory refers to the output format being used defined by the `:format` template option. As we saw in the above example, the format option can be set to `:html`, which would use the `html/` directory instead of `text/`. Finally, the individual .erb files are the sections that make up the template. Note that the subdirectory `html/` is also its own "template" that inherits from the parent directory. We will see more on this later. ## setup.rb Every template should have at least one `setup.rb` file that defines the {YARD::Templates::Template#init #init} method to set the {YARD::Templates::Template#sections #sections} used by the template. If a setup.rb is not defined in the template itself, there should be a template that is inherited (via parent directory or explicitly) that sets the sections on a newly created template. A standard setup.rb file looks like: def init sections :section1, :section2, :section3 end ## Sections Sections are smaller components that correlate to template fragments. Practically speaking, a section can either be a template fragment (a conventional .erb file or other supported templating language), a method (which returns a String) or another {YARD::Templates::Template} (which in turn has its own list of sections). ## Nested Sections Sections often require the ability to encapsulate a set of sub-sections in markup (HTML, for instance). Rather than use heavier Template subclass objects, a more lightweight solution is to nest a set of sub-sections as a list that follows a section, for example: def init sections :header, [:section_a, :section_b] end The above example nests `section_a` and `section_b` within the `header` section. Practically speaking, these sections can be placed in the result by `yield`ing to them. A sample header.erb template might contain:

            Header

            <%= yieldall %>
            This template code would place the output of `section_a` and `section_b` within the above div element. Using `yieldall`, we can also change the object that is being rendered. For example, we may want to yield the first method of the class. We can do this like so:

            First method

            <%= yieldall :object => object.meths.first %> This would run the nested sections for the method object instead of the class. Note that `yieldall` yields to all subsections, whereas `yield` will yield to each individually (in order) until there are no more left to yield to. In the vast majority of cases, you'd want to use `yieldall`, since `yield` makes it hard for users to override your template. ## Inheriting Templates Parent directory templates are automatically inherited (or mixed in, to be more accurate) by the current template. This means that the 'default/class/html' template automatically inherits from 'default/class'. This also means that anything defined in 'default/class/setup.rb' can be overridden by 'default/class/html/setup.rb'. Since the Template module is a module, and not a class, they can be mixed in explicitly (via include/extend) from other templates, which allows templates to share erb files or helper logic. The 'default/class' template explicitly mixes in the 'default/module' template, since it uses much of the same sections. This is done with the helper {YARD::Templates::Template::ClassMethods#T T} method, which is simply a shorthand for {YARD::Templates::Engine.template Engine.template}. It can then override (using standard inheritance) the sections from the module template and insert sections pertaining to classes. This is one of the design goals described above. For instance, the first line in `default/class/html/setup.rb` is: include T('default/module/html') This includes the 'default/module/html', which means it also includes 'default/module' by extension. This allows class to make use of any of module's erb files. ## Inserting and Traversing Sections The ability to insert sections was mentioned above. The class template, for instance, will modify the #init method to insert class specific sections: def init super sections.place(:subclasses).before(:children) sections.delete(:children) sections.place([:constructor_details, [T('method_details')]]).before(:methodmissing) end Observe how sections has been modified after the super method was called (the super method would have been defined in `default/module/setup.rb`). The `sections` object is of the {YARD::Templates::Section} class and allows sections to be inserted before or after another section using {Array#place} by it's given name rather than index. This allows the overriding of templates in a way that does not depend on where the section is located (since it may have been overriden by another module). You can also use `sections[:name]` to find the first child section named `:name`. For instance, with the following sections declaration: sections :a, [:b, :c, [:d]] You can get to the :d section with: sections[:a][:c][:d] You can use this to insert a section inside a nested set without using indexed access. The following command would result in `[:a, [:b, :c, [:d, :e]]]`: sections[:a][:c].place(:e).after(:d) There are also two methods, {Insertion#before_any} and {Insertion#after_any}, which allow you to insert sections before or after the first matching section name recursively. The above example could simply be rewritten as: sections.place(:e).after_any(:d) ## Overriding Templates by Registering a Template Path Inheriting templates explicitly is useful when creating a customized template that wants to take advantage of code re-use. However, most users who want to customize YARD templates will want to override existing behaviour without creating a template from scratch. YARD solves this problem by allowing other template paths to be registered. Because template modules are represented by a relative path such as 'default/class', they can be found within any of the registered template paths. A new template path is registered as: YARD::Templates::Engine.register_template_path '/path/to/mytemplates' At this point, any time the 'default/class' template is loaded, the template will first be looked for inside the newly registered template path. If found, it will be used as the template module, with the modules from the other template paths implicitly mixed in. Therefore, by using the same directory structure as a builtin YARD template, a user can customize or override individual templates as if the old ones were inherited. A real world example would further modify the 'default/class' template seen above by creating such a path in our '/path/to/mytemplates' custom template path: /path/to/mytemplates/: |-- class | |-- html | | |-- customsection.erb | |-- setup.rb The `setup.rb` file would look like: def init super sections.push :customsection end Now, when a class object is formatted as HTML, our customsection.erb will be appended to the rendered data. ### Overriding Stylesheets and Javascripts Template authors can override existing stylesheets and javascripts by creating a file with the same name as existing files within the `fulldoc` template. The documentation output will utilize the new replacement file. YARD's `fulldoc` template defines three stylesheets: /yard/templates/default/: |-- fulldoc | |-- html | | |-- css | | | |-- common.css | | | |-- full_list.css | | | |-- style.css The `style.css` is the primary stylesheet for the HTML output. The `full_list.css` is an additional stylesheet loaded specifically for the search field menus (i.e. class list, method list, and file list). The `common.css` is an empty css file that an template author can easily override to provide custom styles for their plugin. However, if a user installs multiple plugins that utilize this same file to deliver styles, it is possible that they will be overridden. YARD's `fulldoc` template defines three javascript files: /yard/templates/default/: |-- fulldoc | |-- html | | |-- js | | | |-- app.js | | | |-- full_list.js | | | |-- jquery.js The `app.js` is the primary javascript file for the HTML output. The `full_list.js` defines additional javascript loaded specifically for the search field menus (i.e. class list, method list, and file list). The `jquery.js` is copy of the jquery javascript library. ### Adding a Custom Stylesheet or Javascript To load additional stylesheets and javascripts with every page (except the search field menus) generated from the base `layout` template: 1. Define your own custom stylesheet and/or javascript file (default/ is the default template name inside of the /template root directory): /template/default/: |-- fulldoc | |-- html | | |-- css | | | |-- custom.css | | |-- js | | | |-- custom.js 2. Create a `setup.rb` in the `layout` template directory and override the methods `stylesheets` and `javascripts`. The path to the template would be: /template/default/: |-- layout | |-- html | | |-- setup.rb And the code would look like: def stylesheets # Load the existing stylesheets while appending the custom one super + %w(css/custom.css) end def javascripts # Load the existing javascripts while appending the custom one super + %w(js/custom.js) end To load additional stylesheets and javascripts for the search menus loaded from the `fulldoc` template: 1. Define your own custom stylesheet and/or javascript file. /path/to/mytemplates/: |-- fulldoc | |-- html | | |-- css | | | |-- custom_full_menu.css | | |-- js | | | |-- custom_full_menu.js 3. Override the methods `stylesheets_full_list` and `javascripts_full_list` in the `setup.rb` file inside fulldoc/html. def stylesheets_full_list # Load the existing stylesheets while appending the custom one super + %w(css/custom.css) end def javascripts_full_list # Load the existing javascripts while appending the custom one super + %w(js/custom.js) end ### Overriding Search Menus By default YARD's `fulldoc` template generates three search fields: * Class List * Method List * File List Their contents are rendered in methods within the `fulldoc` template: * `generate_class_list` * `generate_method_list` * `generate_file_list` To override these lists you will need to: 1. Create a `setup.rb` in the `fulldoc` template directory and override the particular method. /path/to/mytemplates/: |-- fulldoc | |-- html | | |-- setup.rb def generate_method_list @items = prune_method_listing(Registry.all(:method), false) @items = @items.reject {|m| m.name.to_s =~ /=$/ && m.is_attribute? } # Here we changed the functionality to reverse the order of displayed methods @items = @items.sort_by {|m| m.name.to_s }.reverse @list_title = "Method List" @list_type = "methods" asset('method_list.html', erb(:full_list)) end ### Adding Additional Search Menus By default YARD's `fulldoc` template generates three search fields: * Class List * Method List * File List These are defined in the `layout` template method `menu_lists` and pulled into the `fulldoc` template through a similarly named method. To load an additional menu item: 1. Create a `setup.rb` in the `layout` template directory and override the methods `menu_lists`. The `type` informs the search field the name of the file. The `title` is the name that appears above the section when viewed in frames. The `search_title` is the name that appears in the search field tab on the page. /path/to/mytemplates/: |-- layout | |-- html | | |-- setup.rb def menu_lists # Load the existing menus super + [ { :type => 'feature', :title => 'Features', :search_title => 'Feature List' } ] end 2. Create a `setup.rb` in the `fulldoc` template directory and create a method to generate a menu for the specified `type`. The method `generate_assets` will look for a function with a signature prefixed with `generate`, the type value specified, and the suffix `list`. Within that method you can configure and load the specific objects you wish to display. /path/to/mytemplates/: |-- fulldoc | |-- html | | |-- setup.rb def generate_feature_list # load all the features from the Registry @items = Registry.all(:feature) @list_title = "Feature List" @list_type = "feature" # optional: the specified stylesheet class # when not specified it will default to the value of @list_type @list_class = "class" # Generate the full list html file with named feature_list.html # @note this file must be match the name of the type asset('feature_list.html', erb(:full_list)) end yard-0.8.7.3/docs/images/0000755000004100000410000000000012261240652015053 5ustar www-datawww-datayard-0.8.7.3/docs/images/tags-class-diagram.png0000644000004100000410000002177112261240652021234 0ustar www-datawww-dataPNG  IHDRgSzAPLTEfff999f99fڎڎf999ff99ff9ff9fff99ڶfڎٶ8eVf9ee8yyHI8)ڍڍf99fڶfffڎ999fڎ9f9f9f9999O10eff9999f9fffffٶf>-"IDATx^n0Q=PΌY@Yhw  Ǝ[<" >33 gDNSp3 g8p})"Cnt"F޿E',B[·cuwmۿ18YYLU;pE$f(nn~_ԥߧ>?9,7]Mͳ.y-5Nr֑8o,)tu3(jƌ]+5<|Cm]hţʙw. gyјqJnƣ5^ >X]Pڗ\YG Ս] gE(Ud)+v -d C #!Ψ \Amg|nNQcmW!7{jM!O1>-?_ۭiy8!;3Q<<z~Z+ch[NK?.\x:C,g`ٗQuპ~bΝNCBǟ7ކ>oR&WrfqP0n1]BN''8˟nM/\n(  7XPhUp 7֋Y- Jɟnv_Bs~ {ƥgPJtCM~Ҝ}ֱf5gk,T~".TH9SgI+?CwF4q63 ̓3؇!Y\,v 4վZΨֲCzi0kFjֲZߟ?HhRΨֲZ?oJZ"u-wFj-`-!vgX1Uܼ|TZVE)Bp ?@kvhrF笼 r,n:aiF4r6Vk kM_"_RΨi2q6%oD#geɯQZ&ęk*9S~&ęX=hLϦsl Wg 8nxG?T|򟉳B41ސ&=\t}'}?ìa\mbzaA?UoY8vag(ZF*rQ<{08A1src?cC 8#_)?XB5Q290Fcge!ǶTcaZƻڲ+Y&Y!ךAy@hFhI8 Aܟbg_[qF&`.=\k>g%3t42h=k-TC5O)#̪mۜ1q0#[ |7\k_#%ő})|[1l>S4JloFRj#gsQ0xFonBγ 2[QôNВ2:i_3kvծ65נF&5CdmLUSę8g*L3IScL36L>7zceE8) 5q™՞9!5g0` DpfylleΡ?KfܬMJ,s Ag/,,a&Y"W%*6sQ3Y#gn﹙sFYbr\ 3"N8s7GA/S3N ܬMrEYJL(֘7FƏV:lE`\ckLE3q&Tt8;GRs"?Pg8RLe^3?o2"Mg~34bH~+`agsζf DL5?ӝq3Dhagtg\8 &ZY+3? ZY 3?1d3Djag ϪO~&?̷L̛3q&Tę8gL3}2&?|_L3?P KOq&5LE)?C qęg~.`)?C FμC<řg~0BuּC<řg~0M|ڟ:x3ck3&c35P;&@h3?-<>3s t6 @ٹݴ8Υ*lj.*G. @-ҧa+;t :3:Cg3tβY(K3lil"KgiѾy_;@gcO:}+ͧ-vSgdq|r8n٧ep6VaOiK洪am\)ͧ1:3t:Cg3t@g t 3:3t:Cg3t@g bvl bz^osf:6&3\x8<*B&̎u8(Ddz3ׯ6mΞMY8G{?gpiH}I}\+Mo6Zk9S7.gW}&bdę+ph}_eB1rpg5Ggxz鎆x38/+T7$gpgJlo>ݽ8ͼNh8* S=:ų :gg;#Z]2ydk>ZY'ϟʦ޵38p(R g( ~k-,lj]x9J Q&#vyg9ӷLdgi{?,2EFJh-Zx[ J?:gV#| ٹZBҼTtgpꔩ ?o^4-V4n mY blT2Om_DB_vvZaa9)/IҞjp!4BSRH/t:e⾿M?u 1& +nJ, $63S&[S1YFR ~ 8@83pgpvĂ38ޑ Yݫu\z̳1,3TC5,?fjhpFc͜ Ҁ!$Y;cͬ Ҁ^l fpg~ 83838+838oha;8f,* e֙fig*g",_"3sz,/_i&Vic 򵋄U?L3Yr<,?Ƕ6̮+=sY56;h8vBQwt E^E܂Vc)ތU\kdz)z.jx{4fKB ُѪތy56;ζ;PEg|g!8gE +"gn{3^qͶ옝rDYZx<˗.jߟu5gۛ׶#u똝rHoje>Gh;ɕ.tTfz3j8;f1g.R"x6D :Zt|Ӽ6oS3r_Ő\fk<`H=J{rg=[%:p6;ՐsYղW5/gUʜ_pn?e Wfiun3ԣYx9W^ 69ଇ7S :gT ͷkepy)gzyE8C=9gM%3s}iRРҝ_pk 8383gpgp Ya؄3grc}]1c=Z|K l96 ٬f6Y7c-_mMAzY؄3g~`^l96 Yk,l4pL*$Psl3;}_x=sl~eRl96 g996 @?PC A3T{B`vo@CpACpP}BTY@!8C!g!gx"Jp !838383gpgp 383838Cštk9 bҁ-a \[=<0gpE19\;'z*ͰyEٙV)gpVoH7ڜi>xVM𣏕Iͥ38B lgt,tVqiq/ُ3G=t<+\jvEP;YQqg/QxyUX8ay1g"mp^,z|F6m8R'"I I+gvLhT{8niH8#- l")~Z838738>}?iˮ4^"h> ߭{qWm0m*|QAgp [>v9sq2!խpW(mj!>Qu [f[^>QkF !Jf*my++ї1qiwk7>ٜ^# T"2dqּtb5H?g >93MltP4??g^GװWԔ[#9ұ+poF_L'EmClFƵFi1͓?f{>$C62n#3 v;:K -l>38nv|(͙'c3Yf܆דxCΙ Fmx +hH cU;M|(^7#ύm2Pcpg<gpgpgpgpgp,Հ^48K ,Lfq5`(Y4wDۙk۞ 38?-6V8qm5 쑭jgx ;@F۟ 38?=g?gp{d-q_m.,V[⭵υ^mqf3yQQp30:s?ށ_ \8g!83g I}@QL3gy38CAr0ٓUjY]˟j\EkњEcΆtM8^ϒ96lOϱ g{tg96?K?g ipgy! v!8CpgY)rY)r|(27gJL3L3"DH¯g8gC!83gV Z!IENDB`yard-0.8.7.3/docs/images/overview-class-diagram.png0000755000004100000410000001742412261240652022147 0ustar www-datawww-dataPNG  IHDRa{PLTEcd[IDATx^͎66e$k} μ'5ݣ H Yۃ&)/ɔ)~H,O/(0(La S0)La S0)La Sε%Y>G!i|pi3lR)sa|*tpV!ҧr* ^Ѽ ~f#^b* YπY UIe5F<SƄ& +0 0̅d*].tr!a PP|xlBnpL(vVK ]a׷h<7*\s|wa3Whd /H53`6 N3ݘp' l@.Ԣ y*bˋNF%mjD8e`H95\8߆WT˅6*$S9m9a߫l=,Fqa tLk 5,[!B=j_{Zz1 I[kM)q&]o{ŵ t;5ow1^ě}O8օ%|z[zawǤjkqo0ch,bY = +)0)~P0)La S0)La S0)~@W[-~T| ~yvScӞ)La S8!¶0s%w LM}FEPXM4l.dZ5}$X_X¦RQxRf7y8ۮK lKh鴅*^%(La S`\>nGзB>7>?kc S0)La 7;{*,;jM^WkcYO‰nPX+URn/B$ٲiIX?bړLXL oHXF-FX0jwE&ӥO[V y5 # W覹W tBD5]F"Ճ Gbї3p!$T+F끚M¦YFyH>,^A5~]͹3H6GAҽ$a@O(ݮLŅPX=u)[Oج$N3OXz[60 5cJVXù" WǮj L$ !mdR&H?Mp-!ᤷ% .<jګe,g1 Jc8 aA_6Qºs ^S +6(a/Wq5FۮN6 a1=]6iKlSX& 6!W~)aoO-M ފ)P6Sy9Ca^xa{?r k7MǿVJt=cSֽ==}OMGO&:HRۏ2[{YPk{}\$Z$k Vpڌk) (\ZH7Iޮp{:$<Մ)qnZ;_^}k·݌)yqq2g }p>7SX 'Npם bzoAapPQ_-΂O(le@!.lqcNp-$iŝ!. t #B)}lLEҔ]0k 1#[PqaE .ܫv: ;/qa (nC+pݑXyr= S50PZbé%Al0\PGwVXbl[6`% Aᙡ^OXz/n S6"La SX$LatO 0Пg )8ʻI}&'^΀NxDZupoyضYJ4D^9l;]8A+%(lj- ?0^M0z~d$m\51Ùp%;aMP/2^Jpzt;EV8k:)Y&L$'Cw-YDX`*b0FX--vLETF}"ėӉLb Fŋ^Z&Մ`N*=aMa Ajr8ayL'JuG6 "xOW08Wzyv, kƯ?\? kƟ c2yx7 =/#,fR6Z[a KVœ_B}Ka S1d«n+<ǥNX;pm_%|~L>Lp9(\_C*pȝd0txhPXUMM`brhaivw%dO#S󱀰Q{aS5x|G)pG= u>F{h/{Mu>N2] b"i7ǒtM~On)\ SP\mۆK3O_P S̶Dc{U qtK5Gq)S:/L~'vimQ7/q7o6OS_ /m)|z&a90)Oؔ΄M?6)²^F ?F8uHVxNdy֊-ץV0zڬW_8Kک鮄_\_FrX-FZ_` RMMfZ]+LaBZa  k)l(tfk )4 eٛN,u3a؞Juwjn|OWpEM Lay&Vk/<>NN![ kBOwzRv(@p>NNMB_35b_dNAG)?.Qj|@_ zR8_pޡ[NYǏj| k/]Xna1Gp>NF: kЭ&5")X7P+S3itrJy.. M'j,] w";7UX {Q8 e環&^kTYngd { -ޖ~«yVF yTVA0)ELaOUApa\t^;(Aa cN S_)pM\pETS]z{:,%DGs>l$΅m/ K pHtV/pa a A/v;V SXaR_ҡt;HA{py~(ly~Ef?(.𴪰d .Zbb"Yw&inAAim OK8Gjk}^ ¸,&k ˞Uv0[iLFa{X >p8]a  ?W=/h尙T`7܂0}ZzaL+?*f 8Zs \@Wޅ)La_P=(}59p`0)La S5)La S(K0MfR4IEP}Px1k: S0)) xU}:}~^'p0)6(La o5(̚0)  ޿ #Sn/Aa S0\nzy>[~PmSm(<'d0)La )LՐ S-653I;mIaĀNY7$0au5J -,L Q St0Sh\ۆQmy~0)^Pk\/ ;2˻J§ob-) ~76p"rPXG~81!&&i:nSoM$8%A5icqILa d pt:ᚠ]D:W =#qLYֱ0/La S0ii,?F)jv&٭0)q:(,(l 'p&"0Vº0,bej UQ2~]Lua SX\ĮQDXpUK[i La1Q5.2# p8v&&3),.E.r8q(`,V3̅eAb0M¾ٍV`C-2݀5J6um mK` t=_6_2EX!.}a>0)'FøPxµGP0' SXq] E))q~TLx /+ g.ľ EF0Bh)La G̈́Sk0wA嫞OIXuLXf*UO%.Q. *U', & KؾBFhI#a g$0po"Fz·cZ&|&l6EQK h /p>&&O)TJht|,CZ'Xcpw<#B|AJtp>!SӚN&ń Y6-SXp6DQQX4K ( b@x8ؖp{:mxOG|.Aa SZ5\>NXVX #Nm)V§ S¶0)\g a py~*)\N…~)\gia kRŹ~Z=)La>0)L0[kf*a =bGa?+{R<ϢFsa 00! ) n6Rh'La a GV,4/_Q\Z=" SX\x000Յ۴)i@L#S3xP¬(Lm)La Z syV20)La :2} \ 3e¶0!&[yXaXlF; Yi[TU¶0!"/R®֨`9la%L @,%dOa S0)La S0[py:a W pEP^'(La S0)La43iOI\(:(xP08K}۬M|8ۊ70((La S06#}q9ƃ0)La o3(La S0)La ⛫qT)IENDB`yard-0.8.7.3/docs/images/parser-class-diagram.png0000755000004100000410000002602712261240652021574 0ustar www-datawww-dataPNG  IHDR%n:PLTEe9ڶ9999ڶff8yy9ڎffڎ9ڎf9ڶfffڎf99999ff99ffff99ff99ff999f9f9fڶ99ff9f99ڎfڎ8eV99f99fff8yyff9ٶٶf99fڎ9e9ffڶff9lf*IDATx^݇zqn@tג>l{zo;G/Yg2o_Db=ɉB VBJ+&vY/$F/ j9Vgy2}ILWIvyH+!W+4x3VkS/v5[z{v[NuoW3*}kM]m|[$MN-\˩&q2'>]6֭XndP,o5=za>ԷT ^XwN@U|#rjmo__JКD$ KwjNJ8V]sޖaL'5¯Vcp/kT!h%h%h%Č!ԟg&VVBJJZ A+A+!h%tyA+A+Z ZthE+Z ZJЊ'v'hE+ZZr{u!iYO-VٵVEX&=jNf!%]'ъVf+cv6 V 7w]~kӁ8ɩ[ި}=ѵ{oZop~M6Yj GZV@i!nw ZѪ![{ٱZ#ת׺kS6O["\jW}wmdhw&4u,xۧ=5oucӃ{ښJξb׮ziENtK? Z՟G8MnM(;K^k5hMn[ Z\|:| 4u&I11o˙[Zծ;,vwp{ŢV_ڜ췵Z)B+iF^we_9߼yxuwU]zPjS|oiPSjNNo'nwNj}rLkE+}ke'6o N=BpA+ZъVhE+Z: uB+uhEhVhE+ZъVVEvg+{Q:VUPCΪV4>f[wWU(҉TcߊV[ժZwTF\ ,nZ1CV[wTF1 ZwW5| ZwWuo5jݑ02MIZtٵvZUOV.ܕhoe'yٗo@+uDbLaU}ugZ[~B1f;'Dӝ"3+)؆}#v1emnoC+Z?uw<߯>XwN0E!Z=}zw^ʵL]hoZ+~vB{UZSBZe[ǻnZ{JUh՝/jNѶK=UҪҪhE#"layp!;V{WZU¥UѺogi\ڿ;ת>OU!M^k_h^j;׭Fpup#Zd+7&&zD"LܮoU$yVЪ{fi\8|=v_4kq?GpƵ:h #8NVGp"h #8OV0kkEӸ[IJwG ZGwл#h h=ZZ;2@Њu#h9{nƯ(5`Է;tӷG}kC7Z Z Z Z:M>T쪭hEk]1 n741YgkE+"j/Sv'pE뙐*.~,;~'pEc\>[uf=GW8F٥[Cߚe1O[U֪-V}k ~'pE9*i}jkL ~'p}vZA5}kw}^9ux}kLvHQ㨴UZ5Գ&1o/;ZvH he0@ߪr}3"!t]RS:-=PhEvfof:[vq]^egH'x6# ZU}kWk^!ɾUT&9sߪ:E c[h6h[zR'Էnqc6ٻ۔:~lUXGw}cj]cJ}Mb5HگqM68h5"K@+ZX+A+Zъ'#hxZ5WC6ZѺ/1jE+uUulB> E[9Pzګr= V/Ru/Szگr= UZUwX;* bzLЪ[{2]VrX \3v>ZA,Z ZUXCi)I}X{gXs\fĢP'VVhE+Z Zxkxɱ5h h)hU5Nk?2LT:XЊUVkУxcRڙ06œe:Vҷz x{3KG\ݷh }kGf&hEҽnu`euPhEkp@UjؔMA+ZZ ZhE+ZъVUu ZCЪ)Z.7{fe8hEO=Ir߬1hE+jU읕5"hJ`ϬkE+Z!kשּׁ1hE+W3kשּׁkE+Z!kChoЊV:hE+ZJЊV[c!ԷF>+ZCjqEkO[!Է~4h 5i\j>h5i\:xJ}k|ӸP'VhE+1#sJ^-hE+ZъVVVVVVVBzH:O/E+ЊV@+Z|VhE+ZъVhE+ZъhE9&h=ozhE+ZъV>àUj>h@WZc Z_:rqz _)Z# }V.Dku9KZ̾_[EkuH"x3Ck|Ak7}k*LaК&EVg9Z ceҏ # u Z hE+Zъ֧B|ɳՊVhE+Z%h:hE+ZъVhE+Zz.ZO'hE+ZCVh1E36eZъl%"_M,EV6_z~S?.rpfi8hEk*V7KJ5߬Ӑ}+ZZ`Y;tm VEjl /V7q)#gn^] fj C+ZyR}kmJR@ZъVqx~JlVNhEk3͢h=AЊV7~?k\F+ZZI:z_n{Gm*ǡzZJ6fV8"^֒DF+Zz.]6hVrZ/gnգGk_Y58OAYӯںJ~՗UiUZVUiUZUY볕Һ~J:9^=LywJwf~̒\T0!&{\R#2o&|}_tttXJq4nw3*U*i{D3fE!. hLgݧ%JVJ3ؖ,[6ZFu B'!(K'5@=C3=X`Zo͉|-,UR#S3K N@{N+Mθ (Tk+qwlWJ,h'K+$52^Њ|TvbʼnHlWJgdi8зf` RRJfnGǥhWJQB&@`A+C֥hE+Z׊VъV? hE+ZT;׊V=kE+Z͎hE+dàurJmE+ϭ`"hߊVЊVhE+ZъVsYˢR[hE+ZъVhE+ZъVhE+ZъVhE+ZъVhE+ZъVhE+ZъV\粦S)4szDnBާVeh,W^ݾ-vǔIzql+ZA+Zj\5hEMVA+ơh'@ON Zb/ /Ƅ S~VW5SChE+ZъVhE+ZъVhE+ZъVhE+ZъVh{ʅZm, ~%[ъVhEpZekE+ZъUmJӲ-vl-WϧʶڣAkTx^ O8{FLAkúӺk}kUcr?P}GYjTADfklsДmo}hր[MCjr_/k nQz͠5S)ug=cΰw8R.ƱK۵IX+ZŬlrRVvUxU6nFH_+ъjdGƺH׿ ^7h-۝zuk^N{'󄻤d[(#wkfyRO#jGTVU_-wjZeg2nM3֙"jEklMZ_O;iM_9}h,qpZ[u8穖ehUIU+Zck2.7+S_^5\J+Z[u)/V7w/"zKiE+Zck2.}[ =Vdl]ڛ'ϭQ[Ҋؚ.l > 'Z^MV5|G4<{:OZ*۶:[B8ڷ֪j >̬h}|"p6!T4vw>ĠuU5Hk8oV~QчŴ@ A)@kXA+Z'e"]Z ZѺecGTh0l u?a㻰G ZhEh^hE+ZѺW?ߚ׶bɬM.זϪj*wvmG* $2d%&ؒ9"J*}w:ZU8l&nв$p_V#gy2ZZ nDouw?ϢZ؃S;E+&`?=4L>S*s8Y- Ъ"+Ѫ[EӰśȴг@>N-EGlLo*Vr+,_n-S=?eZ|.05 +~k ЪݤjZ*Π5GڅCpZNiB >uM0C_K7[, BMuaЮ&˭ >hHZ)p8mp(n#U\،Vh@42ų˅BѪIm\[TfWhEV[WnV 0Y.܋V{]{}t!Z[-E+Zoe^U+` $ ] t2'pهVZ!$^ B+ZV)C+VZű!YVvjbve]V)e&`l:ti-*Xf׆*^ Gntt*_kJbS8gZTB+VZesMO`ve|ikG`S}]:~a,F+ZtzoZU,5u]?NZKG%AkhEZB6GZ;u|@(շVKu~v.*pzB2ǯKkYF:ɀ MwޙɯZ~*zZ"J\=;ia+f5e#QW^zsKswEX[hYUxP)$Ÿ|댹ZcDs YB"aVh_(UͫЪ"+hhֹՇs[5ĎͫZ냎} 𷾐s[<| ̫3Һ"ZgOT^<ZO^W'ejjn+kU0GW֚LU0*ߚscU tK+Vњ:Њ5*k*6 hm0Z6  ekֶY,bZuZ#VhXԀJ#$Bkl ƴbP#VrjihŐF8VF^;UsߔκrӖZ\ i#ie~k3Z}wœ+5MHthKgmdZ!p$o^"cDYll6Տ\j.lVj̭㞀x7t0NQjN6& \SҊg=T|![ײZ-+vD+Bkz=fZB+B+B+B+B+B+m [ND+oUkoG`z oU}+:ݖ`ɭъr[;Њ5*-WedVhߪ2#w56U {.SGN+֌|}˵[i:5XP_yrǡ v$>j7n?xt90r ZѲpl=ֺ!#adVhUٳvl=ֺaGMYe4ruYqh&;j^eٙhIEi\d펚:{ꐖ h%hw;egZghE)KÍT]#BZiֶ#d#9u$oQe@'#Ym@knVhm?Zg D=ݬ>5$vV֠R vZVh:"[Yӊ^n^\-M`-k:M?cn:.[: Bk:M-m ůo unZAS#iZ' ASC7Z h=|_V*IZF`{ie~humKݤSzn$[5lQ]cњ +] ޵Uz…r* T ӊUcZ`vkh=?[*Z ~h;:jlRWh=<вƟo{kCJnmw4\A@kȴ# 6Z Z㎆0WhmZw4enl0BkiX ꀴ׾hm`pVhՠ.h'jLrMU iBs:AtC+jPU%r4!>&Dn!68=kIsyj [**ZJ֎k[`iBzJn3- ZZZZZZZZZ!1KrA]C uց)( s[K Ͽ&ʖO5Zg 6Y Ouߪy}Z>xWh1ZLOT:uo[,EVc6>@A ZZ hm J@+B+B+B+ i* UMzsYah`̫&1ςy}@ dLA"\ܹ=ý?i ߊ5з֞5־gj+>Y }$־gj+5зNU'}$ƶl le+[Vle+[VֲY2oBOMv{17oꡚl~+oLZǸv{BZk]Z׌[a~k?_Bڟqo~+{kyZd[omG:le+[Vle+[V[ }듲Wuk7{uGZM]Nmuu;UKY~uV.ˈ^ǷL7%uYBZ8mYMbgt[o-OqVQZ`n+QvL8~bgt[o}U,6/kĎ: le+ؚ٥c"@`@G;d ܓhf+zV[OVlV[VlV[VlV[VlV[VlV[Vl[U.lV[ۊ`+؊`+؊`+؊`+؊`+,va~,!2l[e׎i@ pmZAp @0Sas:6cIENDB`yard-0.8.7.3/docs/images/code-objects-class-diagram.png0000644000004100000410000017312012261240652022633 0ustar www-datawww-dataPNG  IHDRO{IDATxuXTKnnٵv v]kJIcwH" * "0]t+1}}<3\f|sa@40 (B! ^ R(B!O/?BQUWUiTH(xT=(Ӿjk(BK!wwwʤ Dx.;ul\VP vON H l[/;9"*?5'4r ~\ o=$-8..@DžjE~.KW!@}?iF7Hh:OY YqEƔ5k'@>PH*73-/L@،6gkt'< N9&O2a"j]0 L,LV` n_ɀp$u?-rnbj[9te͜ [wt;j&V|Ow+. k5!O[IUs-)+Oo\$bAl^x;KޖE6Dxt[%uS z=^87ߕXl ߑ~@bK5Bc5p V'K t8ՎoVCPaɒxaFrR.< lշbE_h&ٚ&3gcQˎ L$uܸ1,JO@ A|\> OKf y8&& Ȓ8q"Pv Uk}ri7ކͺoh/^ %K^ R/Bx)K^ PDfwO1bXD_ 6|"dxߟh0]:X C_]AA>I7}>POܛ^Kx /%^u2g= /UPG [[*^n,^1@d(`o%?pP#^jh&`XH[ ]w-[J Ubf۬/%3`XpwK0] 6Yx(B Ye0}VcvC6#֐ v%@^!֌l'ivGKd]s1lp,@V7"֌EУf ༬o7Ha  矍"ϟ^[xڽb8 8n\4dKG@R4ME{`4 U~0Dx oeO{yw^lخQA|ݫcsdȖU./Ō'?i%okdoM@]kZ@3 Kgbo_O-&[!^Kx U詄~(^W.xyOx8G"OlWEW^@,-$*sKxoV!ˮ;|0y'sz9Z/ k-vf^p2x`%R6Vk<L ~ pQ=k!=6 5HX ۇ^[x6h*/2 K i="&pW-y>SmEcnF+ +=g;d7/s"N3H hی[GüZ\n~ER0\K-r9Jx %Q6׼;8#u?-\x6bT 9J/^Nx o)5'9U:vySE 4ǹX3{V+z\Oҏ0{TKx,ZP.I$Lbp¢b "c! ώGGGEGGE&mnHtṗ0KxNߩ 0ކ 5MZ@!୑^Kx gWM: v7zkL4OÖLH.Kx oK8x<#tycZeKz1iފQe{~;?ʓlz/2 o@J:%bTYE$mW9:v ^6qNDx o} ϊo$@qׁ' xV497Ax o}M3V^l@dN *hI?]n++blt1%W(7[p&}[nn^>c}l /ϲ@;laLuFb`xN2ךp%>OؘQeRzO k5MXm"׶y8H/x'yas:I򕖁S@轝G\M {ƆޝSx9k@@֔!L]g$:([{:I&^xO Eȷ#<$ Ds/t%$3T7v+žl0#cDsPg/;2<7)xYh40X,k`^ޏǛkHE[m}o ` K&.RBtJ#Cݵ%, XPYF/oM^q/)eS O~8l7 'ړ,X ^Gɯ_6B.q:ړ&HU*\uHl~F^['lx#Cm[~]1x"z'7a;Z9dzW!xB^pY)WyW Ȏ|^[3xz;i&@W?-<3c_z-wc}{kuvv3M?菙JTK(pZ%!ݸN^%5rX9d+d r ҧJxoe%r2@e@(cYr2o Kx o-f22 ;/HkkKxo%&Bx /%=ާGVUO[Y[_+BkO/_;/Maycn#zwϝdn%!YC;Kxko\ee:JFxe=_*.v}R7SBn"notdx]ZO 8Ў=&Ys͞/fD{o:N(iS]"VT}+z!6oz/X!Y~qogčJxf]:Vco,%[*ٗ,8^`zq@'Sp"X)R >!'#fV=`A@gd밄*޼6o[(4YbӤn@=*3K* 8t=JGL6Kxkl()ݥ7T6r*;us|9$Dr:'' jv@[#o7upz>o%bZLV3l(_hΈ4cr1ŀ` n_of2^$vl`O9 n\YD|a>`$pgdzvH8–YӶ%G@@8AZxs\ 8#p%%c<~ W^|U/!W~\/%*dy-WD߶}.OnۤX{]oً /) N>o<+FX M0Gh$`u;}(,2"K`D6I8gJ_,%5*;ߎ4A*'zf>Ln|'Q@!@7GM8̜_U[cM+{87vqkKxkokw]PuCs]9G:̞ L] +FsF uI+=̚m4]T+`oHHKxkl(_]}})At?4xfs`H}-I? G9H'_ GF]*>FĎ59nAJx o4lբ^ad#6 s7YW)Wz%E-Ax ;e0xmrs&Z I҄&@n^[xybʚǤ={"t_ Ƚ/]Z'Z]V2Am7jgڲaiW/ிnW)ї@x^[sx9YE_·m>[XKHAx oΔ?NNsvmr>ѥm ^ɩOBx o^Kx gwWpQ>k~,\L`[K8 7<=82](2"^ws^[SxE׳+%9,iJOX{cJX+y{CxS)-߾[h 2!=c&.v[sx+.R\"LÓZ2Njh( (9'"/2+Oɒ *#blGԴy oYmΖ붥!sцӫo[y s7d+iYcjk˝?Nlt'{9- e\%29:DELWo=h~א ⑦! %)g(9Ʈd !CHQe_97ͼߞ ~m+`yj拀Vh 5H<8w|< ,@QTNPM/ѥ?:O\y>VV/Aظq1:uhw ~0]h'u~W}9^thp$`BeMKA?oW:%5[6z54;XEFWGz.vͣLG1uacOr:قce%Ͽa} xJ'_%5V?{*:n3zͺFG؃KoY}Qaܚn]27UڮiXL{vہfg/a\H{ru ӀGHu~\p|K& uL[ F[S =Jn~(5&_^«pxZ{d YOXye>2Kx  %~xRKTgAwٻe d|nAn ¢b@$[Tr&^1\>Гi<߮?-0Z,a@k`\t-^[xcFloƆxoy8j|0$^$3_'V\0ԙ['mfz5'eK΁^r@kqVwQ\@&0f-at/ݦq7/iC"3^6~ڭnCna=skMV'H`/eξ8ck_-vdba%ρP8,=鈃Q<^V,R}).>/uD1_wZ'~r5yXOx3m1͂Ms }p5)[5KxkoF=]l;>Rwp8w** %^Kx /%u7H.%U\/ -P*DhZ*oCTv s.&S ^«xxT=K['R;y|J/U|T[w-@lD{x{{{{/U<ʀ%AuI/œBʚ)x6Kx /%^Kx /%{.*7; | /UdRNy;_=uxɸ#7SKxoE Q dpoT, /Udyh1l@/ /U|BՀ̻% o;G Ž'"A帼xrųt hiCx o)eIzH6R*#6*kN5T6ކWt%(ྴ/^«x+*4'ͷQw^]/%e /m8xٕ x@`p`Ox "iǖOT*4ފIv;.PH)o[1$2U7_ U]cccc4U@c/ an^~~~~~MqJx o h.,fUƛ''WtU_ h;ǘܯɎ;vlGeUۏa3Fކr&!'bq _%xu/Z"er(^]/%sn HZ1 {됨ҧ_rUl&^[xFJsMc&9[t'ⱄ+ފQe<_৾{4r# ~*lū]Byž%V\ajCWra7]`6e mjVySqE3n%xOv?%T6u-7M kJOR px Gx oMdP,9@ΡM" ҲڃR624޺++*JTu.*(6VrЍWeaQq>z) T=ʚ;'hwL 2{Bv+= {L"X;_@)9aSr/kNz;Nrnʶ\6xItXlQޝ\`ln?&'^ʢe$0~71@j`vzH:؈☐Ҹ$ =0c> %~Cx o 6SF8>eҳBwǢA':|~uv#nC('!vzq6D֎bKx$:%~xw 1Ku^w^[xeԃDfLK=UȍtT,k%uwq$w +=H6XlfOv`%L ) o2^k~vF"u\=PCgwf!q <5H4Ҹ6䦋wbAx o<̛q<qZ7Dc7 (gCp8xD ?GHbq-q_-ۙ*omͷgrMҼ ~e(]mM{}W@qIZE?ǣ&nWJFXa|[)[p5#$(4ZRg|wMT:w;3H$OTG2c@2%uV6ȋl*zHPZ6 օ:>߾-c4Qx@R 0v=t'KxkoŴb= @%8ÜPBdJh~k~|E*T> #Ɖcrn{ #]բ#/#INg36ciJ)~mߎC>f?܇с>7#b_e^[xk!i' /mxx,% /INx ~/)yDHa#I揁.xM'lNݰPoc dMMvӵi`uWݨ6MQh`\<ޏ(esviM>] x4*e1ٸ#:#@Kt,@R%uҨV=#n0MIg/YmΙ#]^=y /M;qH z-ڗFXi$ڶ͹E!Ƨ!\i֭+*cMͻp78=׋:.TSyCQDwϑv%x-2q@^[wx */ݢ @^+,>॒ 1=CZYAzhk%x?mgLuʟ9^qJj]j2@.})װ ;?i8-5#MFx o e=0[ K9΍e$@k[O~tQ^[ǽ ˮNx# cnj^5s$3۞7ZvS_JX#fΚ͗5鄍-^Wy录x{zvtyVX< U2"Ǽy_*=ӧ^rH] ~ %^Kx /%u+f9r@e /mXxGaպ=F$E3!5Rr{ yXT:1IAx+ފa4uƅ\usљWϽ$_O ?o 9^-EP~ӮIlT$M3E77hZ? oJH;؄ig y%G?1 0ˇ|ЋD7m/ X/0U& X/*-b{ Y@bN^^?/ 9%-^7j)ޑc\޺Xyc#ŰY\#xaJjCŌ.૚D&Ӗ؝+Gf #[:MoTYĥ=Li F 5pLsJĻgDF"^gy97f;sjEPM2Kx%+T=^ƋF*{| dVh.d_4t8À%z(l3ㆵu_>}\HΐTŬ\ bQ\$"'ʁbN?RXW\>O(B>_$rŀW<@ SKx?:VQqg)^n[ڠ!O[DVg ^\mOv oEXwKIEj/ Mᘗτ\`d@4ߥee} Ӗ,πUkW0mSVL;Fve%壋ߏ7im#jn0ި%YZZ>+;ovKJQhj^1;ª5 k i: N+gD*˚<N0oBx?{֭*W}n^?pt6Q,:+& כ#7P;Yx6K` vLŵ@~?RN+gD)'_Grg7]U ߽UY\b{&NC8Ƈ/tOP.Lr]E S-)8qc7󒲅 iq@d BT/Z ^Zx+&6=zk˕&Y+5L_4u$c86~fxӻGU+љ  q@xW8# y?uWf~Vx g 7u.cU7`%iNeJ>wb- @R (c~Vx?x*B(ԟa~6jwg~?BhUW^³] n} H|1f>ɅE @Cj`/lEx?1KQmD-^|q,gzǙ_J)kw-J /?"8^,NoÓEs<"|)^Cx?mzVҬX&۫l^ZI.)3^ B)}bT^[-5̈_e\];5[hM=Er}ƛѫz5UΘ`hPF"0'np`l^5{@x?cv(އ;pf~1ǖSo0pT?^Dx?XXy(ԟNgM)_7ӽn Wp~ ia S>?/[1ph,œyeȋ잛 '5x+*p'k"D9i,Xl,q:eW+-\s+rg~,DmT ';FO/.͞H $#U1JO-9=v{ix{ 'h~-D|9/^4w!V. C|8^5~J km˂UtYӉ`JyM^I/"Nvv]YqM°bų x+.R0T;Ǧ0簪' @`h7s/uJ!Fz~hQC"kpΞw\o'G}<تxųfI*ָ>BՊUǻ +ӈmDpꖇ4!S H|~ & oFz=wzrnwr2{V*{qœ\oÏ_u/+媺d,/ {UHoyW{-v\:\An)  _0V-.NTic k0ϰ)db)m?Iy;%qPdO\|D*}ܾMrs_>Şu+/;! ;/Zcael^{LZsbYLT/5AxrrzGތY)ki=2oÍtZNj[ Br/}؟Oކ^sw0#LVx# !*YoMr #6++_hV~kg-{B]k p|9my5mnZTgrYg3 wvU,4|YmELSmjoRY3xWpFduƷit7%m[ H./0ȌhpiQ; g1`6ֿg^5 -55b6aδSij^y2Fq\֬wY`Z9 _dӷ@r΋i:Ns8a I^UؤGxXn{\-_Z:,*jF^+(ɎrD5v ,/mRWcĩ?qo:\7 k/w*9mPZo֝F+wOf {~8(2w4|56~.ofOA GM1LxѸV"Eې"P^xQiw€1|/_ Y6@px`8( 7 }&ˁ;j jExPB cʇ,/KYtclQ Eߠ}oi$Gy}Ƨ:WdM; D[{gf7]neSC˚!)|]y. [w.-y-Nfz|k Sh8xvI ધc)iŵ;r6dځވzxf"0®ͯ_Gzŋ;-^6!"WNO/[xY}\棻 ;'V;gt1X«O\ѝ}OEEVCCAU(>5["\& j/ęUOLTmpMK«yѬbsӪJH'i{TIc@UdR[ߣZ;[~=Q˻«a7Û3L- ׈iwNH+ «m-X0L-bflm{EUD=_[0 kgz (e0aWA#rF2 Ì#;asmύW4d5UlUv3 0jeafMm_HnoNx2͜kqK{|0?;0 mש9n! ^NtgtMGleL-jRDx.r1Z$RJ쐛um^Eeuk&[_'ɷM«`h]MjsxMUƯ>B-67שn !=jlNZ;nwQecu{]uյv펵;i;PlD. P@BB{>/HUa{03̽w=wia^WNE 鴢35kx5&"ߨI 5JjHSU&P,ūa[5lP">rKk {$*jw(uqExy\xNr X׀T?^%)SOɤ]1nsy]O~;ɒ0$^, 3 nVItHh]Lx\QiqSL.ňԍ~fz€$pH}r L8V&(NrЇ2uiEF`6AV(97 h)˘ayK=@E5xZx_USLXs 3XetS[>cw Ն 5o=|'&ClmnNM#~om\͋1@h1b^:>У8v9y"%9vބ$#!-$5)<IDH"ddF i:dƧFH"3"cҢ)@! ʈP1<<$2šT  UL\T&Vy3D7%.^W'^Q{+)EbGR Y3̄c;׻ZKH "oQ:6UoUM^wFFS{l*ݹWW/xڪoxu/5獊яx_m.xjmd59hxu%&ﻓٵovܫr-mm@kڏnPEqzx~tw$gJG Ucjxk6E⍋$$WXTy%^|8%_GK)RwHрK/+f/wp%l h)Zy@7 0Au Oxa(:\PsDn~ΙU?Uͳk|xaBYo^xuéi++^!d_zuS*F̹ /{}.΂c+<=[6%U d]=D`/x7/Q>Gx_Ά9ћ ]NԟGHSUQ "͹Z"kUo\sqfR'|*{\"nY7ޒf[5NroxÃCL Ιh%;+)]bInܯPn}kk{, o9kM=>7g,:U!^ol.0Y4/j<^ɗׄ-"K<‹x| tkp "=R^7d=˼M8Hx׷B\ ~QCMxZ{ |헇xK(}=UNjDA[4r&݄(3^z V4zi/bEZTTn) [:ifऊEG n4^ѓBܦfy[{{;DEw=Oׁ2ZrEW1 5?TPyL$mۿoWe!fj}kʽ:/ykg]l/@Q]&zO oeE7Bq'`rd!G ^Ll?iq#|V%̾ձ M$";@,/ejH PqmEGd`7:)4v`5A ]Iؿ⚔|>Z=I&5G.-k5\2*ךhm>SmJ^Vs uԟeVk&<-HM+Oɔp)Gt痧%%7ywk:yw PfSW IGIo7J~ddֽ95&% AutD6 NQX^lo&RDīeÍP{.*,tQ{k fM$[t_xcVi ^c%%9cmeֳ싰pX ){_k U^i3'j`ڇV .=~k n/\x~u~~ct>^v+PoN3owIʒuEVxI u3DW@i =WOe_fY?H@+7Y5Qf)@}L"1,KoOTסA`]^2\v/ f-KN3cBu\ -mj|gsf=dVA}uSJҖ>'cW?Ċ>J@cMCj}"nΙ+cWW&:ި75HˊSx0>7$X#-68Zfe[GAƷwc:>Ip:,˯̯ɘLV&;Etkkܾ:q ޯ)a6LSrTTР.+[x/WCtt@̑u%?:S5%^Q|j6A;c ^U:S)jdD5DzH~wv=A!SVPx1KAERe)ޢ{jn:le۲!du6877N1'guÄli_=ƫL0C݃=ױd|sV[{3wgZxo4IԤ2U^ k0}5Q 쿏ׁG#a`Iw=z2^I4Dn|}7OKsY AS|*[Y8WBX݀gmBWM˚޴ڊx`w " WR oT5oblhSh^9}:\p̟ZO"Yuâ+[rtbj@CpTV3]t9 mO$|H[AɜRmw$?TCXnLb?QƂ.c z\y:pFustRx}j^7B%ic $ٕ2 Ϥ@ߙ?iuz \d5l6󋸵AywM*,qGP_=x0x-%ne'C%Y;L:E\mzC~(p{eZm^:Jޛ˲UYd vZs۵ֻ"^mCv_4,6>d5ng[=]x?+ uQ-ꈼNC{MxʝKv{sP}eLa'2fԸ*R|A_ޘYS'ǫ fJ^5 _8(G H'L˝o _o;9;@IP(~&kWdZG| xɌ_ᕵ0E%+W zڣgTYoQe\z'>oP(\`lL2*:;5/+4L\im W]rd}Po鍯Do΄:^QXDxK[^haIk#<) |~ʘs̝O82GtjWg涚N l ] |-g8Ȩnpv$u=UzV/!x`x艌Ve'jdYkUM0 oAP!MߕY6fD$bdNg5\WZNGL@Lqldݛ*6^\뢒﫮54s~ܝuK޼NWf#|)*x$Ts!<@0 'w?%=v {~>kI) >9=K9 p3uĘZ&6[F*LZyڪzEdYO*fg1ʾ ͅoN%{`H(d/yxw־jP[3Oy[}x7yܫ_tM25H3x"|VIb2Z<7^_LȌ;NaMǥ7F&ڂi&s<yKcC}" }{3yݶ_b˾qO9xG2@R'af҂x/oؙz4H}x]LWޔ3vϬa0A7= +cUpSgQ6ۓTȀ粦^ǽG%%{i9%'I8~iTCWo*fvB)e_]}x14{^jü~{P1a&fսxUS::/E ‹92d磰Nz.|y4>' d-hE9qRaVµ^>4cv{IIRxZQ#:MQ6`w * F+ ƍ/A 3,޽-!'ةWGP^Մs4o,gr+bQW 3N}N"!'TNkAdryfi6N7v`Yε7GPO]n}mHD G2.upPsQOz`O+.oC19YķY` ?*$,[35Ūţ @#0g%`?XHyus G LzFkztv2}RMUXxe=@08< d^>/%PW$xzDEDAg(eĹ&Ak2P `.j/4oD[(=3B[w}Yt.=)[Rv6-&bc7yIn, BՃas5ozA39=k-[^'\jK ރV*Rd=Ԍۦ)\ xbB+3 xkֲMߩtW 1d&py$2^XY!g~wD9{'7oUo7ڧg=jVMj+i+Ķ^6(뷎+W;kǭ׷V#Żc %'T޼Ea"DѷT .w&Ⱦ_-יlG[eY?yOM%;27{CBVhx{t;KR(bMZ Ԝk+}ե {GsjWW:}gִ~y5CPrxXw`SG|ɞF0z`Qe/\Tڠ_F>^c3]L"ɳI~qbT L<+E' .=I۔,GQo#N9gzWymQ%.:$3j茮c4si7ew* ٝפE\L\ck\,PmF $:慖CL߿isZ)=r6؂9g' I묿GY:%?Ͷ3BpU!lj?WG ;;Uw/jC2]yW RXb4! T7L>(Ga?`Q<|sī2?q/! N vF֧UFpw7e1QrT*%m.)"=  I𜆢tqmh4zfџxh9LoᓲE>Y/&+H}}LJ6Z1nՙGrsKr z=`b-Uy* ~ja㝪K66CV &򯕇]6LĺtnW# p?LM6 >yZ'O6~zƺëđ[8[3؄MC;(J ;gq{;n?GɜN? 19 p'S>orB6]=ln$IߛE ;9Br͒q԰W = p w-: tۺru}ׅ#:t8[lt[WŚWf4Te;q68Xxv /x'y>+?Rv,-\}jx V(-_H۵p?!kIƴm&=^̶xq"ևz-:(l/qn6O;aeOW8n8PqĖD+ οeW'u='-U;eo>qkRjX3t85-n[˃M=\. CtkߜYNPk$M|Y91zYFxYv "qW{i{s~rpn*7~|y9)zFz;睗SVD~NĜ<}WC=jXCxbo+s[J:^es욊 ok +. =P18}Bw]@MlH#szhßkB^_J, /V߿[h(W/ֆcįoE!cniNIeVxHB0GTS`jZP8lc ϏT'6M(@!/hX o3԰Fu}䲱d,lnW M{Kwsf{KȨϲќT<;=?`vuj?XlMUDwmTZP=ֱ{"gęΘ_s&WxEW Q*78UfTbDx T42EH̀FyzwD(%QQJc3 M<&*39"QixY45It7ebkWk=^:Gq9~g(l~QIث w`b? d5CW]`>BUT$WKwmhd bȢy?TS B:볨SQU?jZy9?YP̰ c*%0_PHAw@֤DJ#=v3@8Hb?L;?m|U!q*YLz ^-?[=x]^9!jO[kx})n үk6A?NԺM^W'{ww * #a}u#cvJKùJUxeJ/Ew/0+:Qz9Nn}ݵakTl_ Pӧ7BK OG>$wE`QIת 23OD94 ΎFVA_52>S^w,I(M&d' g ;:'v3Z̓Yg|^mQ|}-KvV|\o?0tB?ӭ'?@x4v %{V<)Bzƒ pk^^=õz8t_6U@ys,|ǺspIMwD1uAMpM9lwk63Z#z6 gdlN`im564=o$Nҿ v8rә, @~lΜ6ِd8a.W5q&}CNvmFhʋ7jVE뛍r"cA)mg9w3% Me!٭g.!> oN576 ~Wdws6Ձ2RNﻥˣ¯O'C9E7rbOy2VKqCy ;lu%]|jV9LO0t,v٤V/ĔDT2@&T Y> P)P(A.P*dJJRY5A.SR2$t`yeJR\J Y6Ǡ a+SP*T@(T -ܝ9<(Zm%GwD=gśN6mg㍭vΒ𲑽 {#Цc!u 32:hgdtocC@/3IiĮø%FPƶ?ϾK6拧2cn%^yFk-׌>=M,^8I W7P!&Y$V`Ȋ oW;(xk8^^J[.0&[=8әD6 '͝!Dm:5MҢ([wEY <+k.h Z !6+dBӽ 판 nfG[C{͒_*,o2p,h+^>^qCD kȢ) x\ՆX!vص6<󠊀ۅ)țXvqܯɮƹ-29x68V{ͥFc? ƏD I!/Q@Lk#Me*Hnխ(v9țLXu޼6&wX9L݄/H9V-2n1uÅl؁C9 V , rjuSiU%U+5)Vh\ k/"ڕu6ysnʸluނ`ݹo>%7f͝"9zsCpo0HFM;T \?hsۨqiK7rث-z\BUpMznʼnCg\+: Rj}3ghTLi9]1sZuOPAnD\*R.*H%d- JT7V-E*LRڐi߼KL@56Nښ齠:5u/v./_zVrn40>oEoxK"RxK-dn<ʛKt[z?oIdO0ms6YvpO;@{L$۝ qϸ#sa-oHlmmΞ 3(n&yTR7@LX%i7?ڝ/_%i׸r:m=S*A7I<_pRogCIx \;c *K57zcʿDtPpƖN/ %TpM|xoE:v,ZHvpTa|WUM>~_b#+!f:WLĿ-w{ʷt^o\U[ L0bS3v?$-R7/,hlut.scݓJE @WW-dme^@wN51Ec/V]fEvyid*#Xl6mo*k֨Έ.71$.pl۠S6#uU#FpZ8H2]@J26ӍL#~ mqU;(S?-FH]+C$H)kt>O=hjzajl5. ? pwB!}Tal\a.ϓuw}W^S|xOtx(g:IOwRx_sOMocOW zoT=$ͬ:_y@s抬7m텰[,y)a]K)RMbaC'[B*-pǵ\:D4ҭbN=QZ:eO yހ2!oFX}m;?^~- Lm$lbP&[^< vHd6Gt'YIggp[,EM-ӳ>gS%aId]otxxtCsm _ʻǍ{c!^/olWUm `?pgӔ=lE:z7yɝ{~ {Ug1ײvp*d2LQ][wkX~]xƕYXyd#JRqk"{}x KGM~W-M_6|&^K ڷ[;UJodI9y,R^U׸(K Թ95^UYq߾Wbfۣ7I+-ߜ ۴y\}uX 6o|jL4a;M5+-MKL4.M~ <>*HxV6ljN,[fTBLn4֨7lʒS}lVYnکJf9M>zL(o :)ʸA4_8r xlSLvNѕź9cR:;/By*lяP)Dy@ "n.T"e[PL *O|(UOv! ůw$Ԩh=E8 *ʤs6ʼn =gӜ:GHU%SpjDU>r[lR-x=^÷6ڨ\aXT?m|w f!#ec*8oi}tκ.3{fej\aj_=pW^wL)[yV}>Hd;q t3%\ a_3H-G8yҾE]%p =gf@p6LKxF/ㆰOz_sYRCx[}}(cėݟNzfb:mͪl"U""\x+N }9=ٽm%gl&l52%r/֢6 E~LmvdFTsJEG*SDRӷw;(x!UsYe+SM`ƌ[1Q`c@uYo7L]ju27˹[Lbev {N;8{]f K탰ES_"7 o"as#Ƒ7 ~) q&߾q ,7Cw<stgARyv(NPcd`o)/T*cbɖM;h73lVRi*wAS}ޣ9849iZW3.[l`lllpP?7EϞf'^Ot |t_6^p~<3ԼjE3|^;Pɇ~lZ}*[]բSG1fWx2oXȑ _ܺ_B|jCV4gҷzoOEYʼ2ڀ" AseeJ~x+駹1}]k<PvՏ'x*O> CD)sr=]4FKxQ٥/# ;9'=Xkl4+Ĉao8i&, W޶v)^X.\oz -ثET4;޵{Z 1JsJ-[NԴ++`*U#*;Gpڜ`C=y/^.YM|j [!qY>5{ڢ; w[hV4-{=srNawfpl+7{_4MhHo^mi2W9wCG@\H 'B_H[mhW~*;VٟtҴ/ϲAzo\9^N(L/.q>[Iz._ԢM6^8x|Q㮰SYg|mhxu^ލz{8! WjټwT/x{z_;4֧ISg%lmڗs=+ļaPP].d/ h>۩A)' ;>?wC̲[ę{;Bӗ[ك47lruptu<Bm999;}L2~[[:@~B\PJ/y{r)⊣s*7{H5$~2x ` a7_xz{{{F o5bEWP=&O~ۡT*<70e_xիCW!`ߌWα˳y\dﯿ&c:bky;ղR^/ сQWۆox_U96Č1ʈ22=N4%ɋoPĚsMT1T8g3ks)ReCwx תʶ`1jC_G$@6sb[] OR Ğ}5:t1b 3|3L+t}kMkSMc\{/Gœ?D`oؽnlߵoޒ};t/8T]sۼ+/:0ȁr *vt UT Ub۾ m(4xz`,}Rv.1O/_t;%=R-Txabݎ&s04;2'HΊ㿞h8yw=[c >R`Yr=+7w*uıVs]$mKe mN:Ox_*X'/\d?>{ocK Y^W4…W4*՛ZxGg>ZV.[z@gj4<$)Q#^AjpF47q?hXo!C Zox[lRsUxF( ۜ9ʋyzha\T-xJ"Nﯶkq#Ow!ofi.)ϟ[/)[mxv&Ĝw}>!i-5bRF8;f2i/}gJ"XMmjg U >=:?+wCm\Bl\o(.2<{R.oJ o^IdI>]:ߨ;]`tneo\G$pݶ,&u2WpsOy޹8=qģ.7 8*ǥ{k¦~mC`ۭ6?3W%vͭwT,dmsH:ujsfyۃ2  EsPzɃ^m/Whܿv1 cPmk~NlaG%qH4]JLX):.UVicK3'gs*ژ`m"6p)_!Arơ\:k%onE3phN/*+%el*ۜr5HnZeK%=jަP Xgp)j4gm‡Wh7LuF>*k B!X[:O+{vƵi+S7Q{Xer;<n͆I:C'7{ qDkhb 4?vykmqUe!=~=Cis܋lK)c*J_t8V@ՃI_ކxh4 5-݂'6z:\EK^W [kR[4{%A.ކ;L~ Gr½EJKEa[{ /lixu =/F$Yyo۽rJ"|΃D+dhtIn=J87LUYx:[H sۼ2 :Îp|;:Q}cRƠ!8_]9@ɩcwYt͈Bs!Iý}5p3:EW{t~Z:fgldK9Agt}8x\* T;D<x +Ns<2idkop;FEaD=fj|sr/p`gM12Ijj.7~fl /$aԀ%WfLgauV&Hiʵ!ބw3Sa\n|]>?xƜQ't8[XAI"Y )a >RDӑ[Ht EEh -&6%56&%(e*2.=6I#Nѐ&^)%k)( av)=,XMB\xHI&D*FDGF'L-چ}R.?M:z!WGrѣ1tܦ WIrڵ+ok׮] z+ m72dṑh=Xkw8CO6SxxgLZP2vWaUVj`nx5r[^^ZqnZ<)9Wc ,8%l}"Vϥ }?6bW +^𶚒}gAE?Lu\;*ĭ6堡vYKG;8ud/6o7tԍMC:~_2N_)޼2MߓN"ȖԾ[/}IQPgo΍!F98bEiO⨺-1xunGfI$riVW}} y ]twemas-}cnR+R iVQ~~O{VnC  WΗ Wj_X¹i4eKU߬*2W.\hnt1 :qs ͞;SK<RNɗfCyh춰7񞮭ToE^ڙ'R šxO_B yxvr%5ٕӥAR6e%^")˾ qzeM{?URY߯Qk͑:DAiE?+koHaai}-IT6`NRh+Rj+E2 tA1q=~xE njw L۟e7p (dCWx{x 폏H~52 7G ^EX+x[U͜XqZZƎ3xIK.Mߨ@wdMBepq}*▍q3e̝.6ۓ؍^;c/\_uFzqc9]\,fqiFƞ`{c ;xG{VAa!l 0(ސifff2‡W?=+ "޹ِ7g8T)Hx}^_=zuMn\*(r/Rh3šݻ*BT!C )ZEZML%<]#|dyo1TմisCGmݙu~фW>`ߧxE>.vyb1lid_uX!tP0ki#?~w^?QۉW9P#TzΥX!Pǩ2Y6x ͋`CF3i%(Jyxq.-#iK;tiۏP}fCi9+ҶR(A[Ɖp@T[<)Қě\{RSZqh\AJk%͒{ioQ{$ue'9$m<po#IEc(޳rncv<:w;\|hݗW9q/l%INE]S$IEF(چm$I*gqx ޺$Iqxo>"߷ݣr$KQoSy̳wU5TG=oq?=[IfM~բiYM*gQ#^ERB|>%|VcA>qx7?X{ڇȺ āx^YIZvvEuu..IUk/Wz*N$k/tMıxڒ$Ifm7:(x ^=Im?[*^$I oG\+GS}xV-˺w(J eܝ}8=zxGQ#.}Im;D%x#z;Ts8o 7 7؝nc*=!gw> '$~6GUxTI ;٣{8owfӈ*gP'DjKqx3^xPX7sԱőx/|jŰ 7rXw1k%_SwKޫ8o>ezx)~؛@?N]7h޳+Kf?W͏Lxje1O$Nodn13fn'w` `!+t3o{[o*m-~xxE )^BűW/Miflr(Mο^Avxe1?vke?Z3]BsuMrQ˓4#5 ?~zCǫkha>SRo(^yo^[0 `hlaoW -e>j bEiD{ićśyͳʿ|ioX-wT#{Mf!"~xwPF$n)[+97>*=r͒ĻXӬZkA.?kt-;3wI9D}(l&+c ,0;mmx^Wx|TM IeI/_!!AA"Mː[mݫ]xk2'†WCjcsAVos'w%F;|9Gy ex;/[*ٝ-͇)e"@07 =Q0*4@c"@3vCΙ9뫹&R{&j u.Lί?i 8ŰN9+dzeaG,g([0nhdUͷLjj4|ݹFbʔ)7HXu)88N42 c7O]iX7<3$5pY-1h@⩓,U8L6ko_ETg5oT3ѕi|x7K;]L/m`Ӡw;ر]w{[ـ{j/,N7N_x '?³o,c9qoVƆSՙq,w7i.ONhf݆X"k`ۄ3 +Hiu! Zޏ]ө'ݚysW: K~@ ˕# 8B-\x^*xٜV^f^~7ō41ô3 =6lA^ʙ/7؜mh+d&2>T;@׋m϶>u hB]xsg@Mլ& ǟ}Ɛ~hN)77W/fdݬscYRu1~q8rqT`{tY[Nioq!A jqRkp7L3t0男5Wx88 vc zg^~xs ql4.BРzְP3ʒ6gj]W?Oސf\+ξAЮR*/Zy 3,T&oO}(|L7y_XOLֵVsRm0w*BWν+-ZOJ!T;@VC+xtwIW-iʌn'/l Mk$L̅-r2J֭ތk P 5f8Ϛ&(髝PF]%59XM ྾o!Û6xM2}-N\膳471˓c; ^ű;*jֻ~Ȍ'dw\{c5Ds5T;6]kcjE5 s>]WM5pl)t5j'L۔ܠ@_l4ƱoVLmIȣLN ?d @18$ (ކ3;meJ-;}u綹˃Rڵuj$ pw-*Χojn첊;[lv@}tby5fca@"#ư[Pf:XcU+0)o•nwX/FK 騷{S^u{N>*iŠL@v-{֮w?3Ip|dyjy:11-SŦYefoy<8p+uv@'nK#nWuDW}W~9S!wZn𽋇R3MxjxZ4Qw=ӏK?"oTrj)v/wg҇/s%%k:wz}tq݃[Mb^]jdO˲m#=~8WVq=  g\jS3KIW(uD wLGK3v5<$E  K$^)S}jԙ724g`j :0c(ؖUc@$C3L'L~$:J^b%;Ť J-$!nI ifq M|Y'6vg*.$kp4x޷Qׯd? 0E>SLJ{.&߼1: tWUemn0E p\35U:[]FrEWB$/.%}?NN<]Cߠ>Ҋ]~j}!*Sxo#k69N MmSU]#TG;^8]UA!z~\,I]5F=?5jEu*W}fC~tNXY/ ZaޥJH~:J\ȤZHJץ`Y.je4FJH[Ai6 E)[bHngi{&di+fݝ8AtMԼ֨u.!e!uS~WfmtVq03KE]jeX폹f>V**ԛ1xMݠԬ_%SݓnʎI-FXt h㤈MUJgfU޻并#uނ7*oZs̍;( K]ƽL=.w0bqJYpyd]fxn39l\``MɸY\4ܫ[sfL!USMf҉]b|Mɶ;cE5؄E1'޶7!Tq|3-px/IBt^㫓& ϢbCH "]@d`!'E.Y*@w?-x ^s+u|VQYֈEoN͙G涺.#=WL"i^*)='nފ6k d6Uݺ\ ?$e'ez٣|/33jZV'~Rx~w)C[_u@St._qCu}HwxMS$}0WlvZڥg5&#gك`o7Ļd0>cffE+-ӖLPu<9]VV\|]/!Nb^V J=Ƃy+Dp,>F Nۯycf;M zq׋`=mSjz-p."$<|ix^-xo?<Hz?݂]? .nڸ/׵+D/{u͸[oˈz9w]^ĠyxS@q%Pv 箲תʦ6m6)0pڹ 3ڊ]OiN3ޣza>heL3ڧFgU99yoň 96xֆbg',"sdӽ:_mϽo*C`0NwZ=OxP}h*:hVJRK+t<`;'[H囜3N_C%<,{Jï|k[NjT WMs޽;Ao=k}{nIZ_ ~,/vFS B}U~ٵiVQo-bv i JM}SܿBo~P b76Ue?h窲{ې@+o|gmi"k x 4Q6|a?[U&00oeve5Lm7]-<#ɫ*ʢF^y J49e3ar{4I%s wwΐv"S_UeymNGE҇lkFʗR˻IO}SVݻ1ZǘYr铐oZu,Z:!/yh{FL=E-9QfC,nx 2ި's&א~{W8{|H1l/cͿ 6b^DM9 ;pZ 6[ _>4|ʝf>\EN3feqi .#\ \i>J+duo<,~7KH}H!ī[(I_ML2:$*4xu:N7}x?.$Iբ R$I*CU, Z g_x፨!I$-|xeM7L=xl^,Nӂ58%\lɢ_bCװI_jљ I[IYqbBD(4Ȏ k!_z՜lrǡq N8c:ePXǍR`tfWsz׶x?=5=h޴Es}Y#Z-M"wYJы4iLdR!KfFXQ:}U`d`8MwO{=MŒz2f[vId֩AVd&}~/@F<@*Zxp+ľrn @xG!Pem*f0+;m+ ~tƲe&1k{HZ.FMǥcz6\. ﹷAͳa5[1ryQ>/L'j&VuN4v.]LYÝuƻ9* ^{M^N,q?OlRx ~^Y3}m]}y!6^Ѩ]Wm3"@LqgҒq.Bڻ=[+m ;M|WXaq[>maa1߯S [C]?ܳwxK?Yc=&utXөL.G) ""+""++""+""+""+""++""+"""+"~\3 dEZRwY_e՚?US ˺ v\(‰B]Wx^Wx?Z-[@M>U3>r\x fG e1/1 oAÛ`Frs(\N\`X{3.C9m WO]Jr>z.5挭Lx?>;~_~8ۏu]?9lN-rno$M:O­ڃҧ̍tf8tBx?Sk?(]abwN2]|Ptta1hxp 'k?~x%ᨬOonnfSݢɉ2NG`y'o͗v6Q6dy]?ә5gEx}lolaM;n> YGx? }X-"@/RPW8h D) UtFQW6z5 86 GdKΎMwmj1|܄SFlW/qӍ&-q!QB\eLrML|VB$GE&IulrT&RU q1%Sx?wɝC otW-x2)qYxm64?\r¬&lgAH^6 DEA-_\^W6+ 㗑o}|!yvJx_5ɿXPWCmd\)Vxoy6Nxlqxkya2.rq'c1"ݡۭ&4 p|5#ƳN.ytq<+3Z<^$5Y=^~r;[BIx UĤv%(̤m3ٰ%yA?9i]8z}உY$!M{ ~]Gkx3x|ū nOJFYHѻ{^9 Ná.b?y`K$EhQUCu!QХ#2ί6kgcH,x,(s,+?~=$ã"0w &H(N [UEql%%[P74pĢ ͼ^;󮗟- l;s[IExX$VV,azi"|{" 8nVj:^V&vcATU >oy'. ܩ#(jܤPe%mNrZQv:B=y[)Z.cW+}_?mYfU z-%&NQkJTx:N?6llNEƘoy^U_]wྺ@쌦S7SƎ6g:zpxs:?u^I?.:^_xk ^Y?W|/8sZxk޿"[c)N?8+g!vXB|CȢQ b)+W\Wx^Wx^Wx+ \Wୡxx՞F%OOOOOT_Qxmx^C`y#ɓ'OIsM^נ>oZ" yAAùhMVx ͭ%_-ٔ۽T}x^{kٮ.AkMOx8 p"?3hCW5nT/ҹ]?2/?????OCv>kHxV͟4^ό6LZˏCx_ڛ՛R}kx3+ + +%1[S:ھRۉz^ߤ( 8^՗Dfplj?G#_Ιy R^9o.Ȁ&.66666:+^,HsNRTT*Jk`xuYY-6de|h+Ph lmmmmR^?W\dM+wVLi])x9~2A}1ǂ㳵__˟{J- ;4} HƓj&\'&=7g_l<]hJ =TePW]krkOoL<NӃUYM-f=PE{5pa1)?<Еe}Ͼ/_6ejnm“ڡem_N~,l!jjєOiТi+ot?zߪƫ/,})%ܚciiiiij3KKKKӭ7lr(W͝B>ŅsBwJ RW6ՁwU dm__:B{5lAwE\oXL<:辀3+n> c).3=7%A]b? ~*@KiYhR;R%q_LL+cjv Oy.)bQ[k,jЁ'ފޜx ٍݽ"G}'JlƫXhmF_Ssn}J/ &ጛk\ RHQ\iX /|5:]Zis):zm/J7n4Hw~+J5ҹ@V; oS"޻m_!L߁[7@$(?^.l^tyh{fz߳>Pz]]]]]Oua1_o*5G~=|\Ɨ]{09T\;Sr{aI;QZS="UNwO3Dı|]Xؚk{.Jv/YysXt.-+K߇$.gkk-yWRv/u+FivKવ>+[7X-KלޜErò,;7=(B컏·c! ?J\jk,EP<HJ4x_&_Ӎ*T-*}`cus_]8><O:0ޱo2|m{n΁mC{s.~њ88:Z;$`A=~;yC}SCoFc9;رs=\wM#cPAZ'pU<#p=Z¬J$HZ ˓_ 6+Jʄ@uSdxJ|NBT}?T@Sx74DIx"'A# Â!"XL *ݓ| DIiAZH U[A_UVh>2Ҁxrsp캻z;&^ja'Bū[$?3}%}5V@dIgm|RjMf b}MytZx ,&qb.[ۏ T)U_UVq{qIǩaH [+Cl<^S"j/]OWh=W:F9[sX*ظgӣHykxc[nX_*áeU=lSL /4piJϩa>e\5x93UWk0\ZA+W5,ѩ:4%@i<>ouFx^9 +V'H Ȫh=o|p&o}НyGAaM^pyŊʻ9^Z~s -DAv-+hbEAg__!53whkt#mD;z h.xުۺT^aB$gډ-t?Rk g"6ҥ'=gXAɸ[ux>>[^,qW,_uf?4>aE]Ks?6[uxUGޝp`f71St7~Awg98Txk~1Z}nCҏvOZ059 >= '@]h^}Li7F)Q /O%x ĹpX'YAE҆[ q `]JCqiew:ϗu]o%YJ7#]I, `T7fM1}i~ ɰwx~.Ͼ5|N"η;WCef]9zAVg^0y`0Wx^נ>Od$ /cw<:F\4K|.9`IT;Ɂ҅QKOZvl_/**W%tPwxfxy6^ސ?i˰RsUd=JYc<.EPPS@fQwGQ b2$%SMՒq\L i9*P%=zaJPEG'Q[ j7v[g'{KKD󗖬~ fP0fo-jxt8n2~vdn6]1+)_;3u^z^yC|~K4#x™?6xa t-xz0EcVh$Nr:8atv}ogK(oC+£Zоn4a8с}AAW(how@!p:kt7ƣm<},rϵ_ /ia#f+bVOn4{Xsx1n/V"5ɩRYAMY&&:N Ӫ;}6z-iDIxkTt̲ez00`|l*BApW.5m֩%S 0d |HqݻD֒BWp/_'J@p=0K xkާ%ڮ^%K~,yF޿ĀvA]c. M+%TfJSJ45[PT '>iRܾCRWkUw]ˊVjⰍQ2N/&NVr Q ,vNjfO\q$537˰5YRH}mwH1*[?]-q^ͿO_YNy,QF{3FT-_KTT5nm`&v6 ߚ@đ}-JUc ^)"ͦF̕U5i16cʺ% SAjqB[UYU]3Gk~]Uv=<pw@B\<]PdŲ+4[;w?t~vr._Ъ7L=Ap㍂['S=#0;޿j@ЦVMi4c۞*{[ OǛQ7aa1jToŽvxWPYP֡ZF&N̅Sa^~dsB;j?'U0Z*iU  }9hXH8L F>p^o#y5FR/Vv _?[{^ån~>p=Uy>]+`G03v pE*5[G[6퀑j<;-Qː£C$:?z9sGv nOtU5x6wT/O\OB=sBɩ{]MM; }cRJu;^[inn?~5sĞ t/|J ιeAPۥ Z5x/[g˅Io\]Cι>;p{h+0,222<@~+wt҅ ̫i5k݆)5_AO 4h-h冂wNĘذ_jrh$aISWM;viiZx=(>,~ #4 k~  Ƿ6=`cn˅ӎ J/& 2 ū/=sKHc_<| :W58`zH Hf2iLx bFs<bv#ʪ\> l1rgCmxř3&v$㟎,2k|_^p]:=V;/ ַ.Û'I \+x^逾˻Vm뵉2'ZY/_URWKI" buLf;A P:" UWtqIJ''\[I.`gڪH=j;x*[zۻ`S,CVW)2jߣ18VJ_%v zB|b=:4^ (\'ɨ}.[agک@t+V *acD;h%:^Y dڢTq?ͱ.))*+yXx$R:UxmVqt0.nmơK%OG6.2dWWx^?GsKKE[JKKKU:W54)D^ڈ;9<*S^j;6j!84X?;gEԨO]d, Y#W{7Nټf-[\B#xJr{ֽۚ-X>F! mR@jaXY?Yg/v֧v -;s !K׬'E{R|;7o3O3cV mUQUY2Sj;G},dE9ƣ+ap{:[٦a|~;hW~~kdtɇrM_O㐴i˻e+5m; 7H4bx.~^8E@~+ܕs}}>&âډ ݝ1J* RO$ $qCjYgN+> nx+ۿ9pI}mhH%6=i9ܨ/O>oN;ܩñFJEWN1?|fs|idtUe!?u2y'uoqNz&FJ.@'J_;\) ơ1RyPLpOr==r RhŇWT/5~Z 8н{Jx+$2>g>(w_}O7S-rRGg6"nC߽ȧ[Q痲7!'I(Px+o2͖MìiL30 prl mAH^^' W>V&G⣿wӍ$ֹ \kfe쑖6{aokZSK)4YH1 VޙWPI!/2C?Yl=y9KG,s]h6Fnk΍uMoyqZN9ca5=-:7IDhçDZ8 xJ\2Y&8/w| &QtrrW4O~ʕ_A8q]Nxś_*HT )19yQP4:qq*ȍOIBb<-b8- o{Jp& hX...'c^DtWyxEAvGa+kn>W;ANLx +'Z] Wm?u=@y^אe;Lک#Kk/ɜQ %KXkq0T. }n+ow,fRj#VFAx b}lL>|[9k~m+7ɠ:&>Y/ WW(}U&ldސ6v{x57^A#ek}^Ng:SSo!%彼+ޏvW}gH;n+p1kHx>=_XfJQX&|f>hCx Kw$ҎCx+oOɰ[VA^Wx'OPoM;qsIpPNxw_?~W5dw7fg7c5o-\X;y7,M5 ,*..... omU1o"nb u\5$v\R̺xR6~c?8ީO2&6[xuY-gf1 lFe_ں'{+'Zmx b,\plhGZD8FBh?݌3srrrr:)xj6W}[s h9'qT}5ӈuE) ՎY;2@A맣pCrKCj׀~RZq@=>@eŀ/II7 c'k@x0dXfJ;WWmלuO+,ǽ5p{+ 8<^fP!DFxdH7 Zx\Μt2 +""T^jD =8'װisOӆ~oIOXaxE^WDDxED^WDDxED^WDxED^Wo?q">UIENDB`yard-0.8.7.3/docs/images/handlers-class-diagram.png0000755000004100000410000002550112261240652022074 0ustar www-datawww-dataPNG  IHDR+6kPLTE9fff֋f99d99ff9dd99ffd9fd8f899f8888fff9ڋ8d9f9f8ff99ff8df9f99f99ڎe9898f9999ڶ9dfdfdd98df8Ԋd9ٶfڶd8Vfֳ8ey9fk8yyڎf8y999d8dfL190Odٲcfd88f889effffڎ99f9fڎ9999fff999ڎy)IDATx^j0@QCϯ%Ȫh(duxRT5/ _ VQbE"V +V#SX=+SlŠ+b呡RbEXAOHs[RGߡXQTVM==͊X+bt:jE"VXaV.X:!V'ܲ)VHXKYR&+~Xaeg,j+]DFCϜAnjd(B"i/+·qn)c\#s|Zv) ZŠʡ_##3H +۲ŠX+HĊXk"sEbeHV_X5kYa国3m¸` (|%*j[a'NhP=rI(֢e~~ڏ<]|"gw9<a }Y9?xɫAV+b|ߙB:*''3$gC{X+U,7Fd~:ap疢6n+uWʜBhe#PxpX؀+-+ ZYQ2$|RYXd`d탺X+ikm `~5ɪ:V$\<؟p ضBܙ-6nz{^+b?m{4~Oâ{VJV$+ | + +bE"V@8Xi+DJK_x[Ż*^a#L/mIznNfy5DJK_bi A]Yo?dx_b PaS,)RZ*`E9**,PWvX*-U"i d%TZ`EqV@]aWJT*ɪUXQ^+nJe(-bEVZĊX0{[vq]+oOr{Ru_#O6t4+Vp[}ž۟6`W`eTZ+8ʮ~~"Vh(m0̯>xE#Wla`}'6+=­Vzh9mp+{K1#eE0snq9GF{_0~V> { NgHelOjJ^tˑ udoE"V`_bre|LtU4+b%i C} rwabo"Vz*qtS(+TUZ+7=GѬX"?{w+CM ufxVNVdy:s|xkdLqk0 pX")nzu-+v+:0NV8DGO|*EZ 9+;AvN +U?(.bt,h3m[JaE |_J> aZg$RXµB[K@r Po)+,\Θa!T VxNX|%.,ŒR +W %WP%l3zd V䯀J h30#o+E3<~X+9~XWĊX+bE"VĊ=wY48ҞJ Wq$= Xmox9*}T~hܒ@S)+ [lYAy~q$<s9d?!oe+n(+aŠT sz8sP~a!EgR#+q?;0Xqe=B'ώن,>BN'(ڒR%+qO@m_xBvNg݂ϓuXं ô,'((I+ ôDV2I@Ng0L$ s:Y4LŊt+b%m2@AbEfEZo; Yl%U+oUV2Vʞj [M?Pl%cK쩦ڰ9 $AT_ d~=T_Š*,%e?5ՆWsd~) PSmx'g~j"'a5$j헕E _SMNXŊ2+P RdM"V7X&m,c]<}r ,²,c`V ݢ.u%Yvʲt_|L,_SF ׺(QS2-aY qE+~8sn2YaI,00 d+ԱBvT[XcpV+/Z Xn 'v䄲,00 du+1?q ^, !X ) 泂 xfz'eeH'53k+e!|VgV+ceP'53XINXIVXؤs&JJPy嶽ܜWf٘~aw9EV+^#θ&V y<&EV+^n|sY ݕ+di'ƙċZb%fɞypVKbK\_!Lrô +`ŋ/vhda=+bEX+bE"' b%bJ2J*ePD_A!Js䫨]af瀐bG򍃐9 ? 3pƐbA$gmfv +5+af`!E9IP TQ ̎A'L+bE9 bERtw!VbN{)v_0fK5)dj)ژ!0[fEA{#+ 1(pBYQ9W+^Sij-!0[*aEO}`l)p'9|Z^t &aR+bIƋ)s L-zB(CXQXQYQ׀XQ}P^YQ׀XQ(k@׀X 'A!VbE!VXQXQk`S:Y"V^pV|ˁ bNKPXYo&U"%d-b+dZp :rfAu+q `}r TJq,8#z٤Vb+g+e-9HJ ast$,($V5@gF7D~X+l$VĊXQX-ĊX"V䯈̐ŕG,{q+W) V=A@H_AL+XW^AĊLYW"J Z{mۈ< ttEE+u/0UÌBIZ~D0$|N3S$_VD#yDg/y~ +9"#\"aERgD0VaEXVVaIӤʨ?++Š +2η"JtStj 1;VSNUmlAX)Nb,fa%Ddź]hXa%Z-+9u,KVN)aeGc + +L/ÉNJ" XaVXaaEXyͰɴr8VXaEX5t +++]_QSU;[/T|)٪^_|٥VBvIuJ)fa(]*Xaes^V9/c.rIYWֻhT֕._})+7%\"ÿhSx VmCNg VX<nw VXQV#zV4ߑߊVXaV.+!s +d +ۓ{:J*- a}< CL竺b+IM)X}T+m BElb%~Nz+Iub]iw'ŠCه\{P'7 Y + + +?JwVί?Cr~{PwVϬ]fSϬn + +ʘkCuL`x+VXaVXaVXaVXaV@UYsU0bxކi+?ok*V˔Vv9zQ<7 A+&֕*) MيAH>e~%֊ +io>ey{Ъ.;Tк6+۲JgVX)Xa[҃ϬDx1=X9<+^ft*)Y9G>gVNrI,궬J~YaV.^cޥm{+YaVSJYa%wPcVX驦 +]~V42ٛ:r[ + + + + +>rVXIVXaVXg)+ + +2| . +22}`Vg\v(l,*,ʮ uɷy8̓< }f&5m*9X4TrT|>N=_}<diN7(\5S J0.lUm'>++ns=W,ݓԕ"sojo0JGq'ͦ&N)5$9ەuձ Z޶+ϸChޚ*WuGWCGF\J#W|vx Zoە:I5Vsތ1Rn0J`zG ~"cO)ypűE7]q6;YT3WAp@ \a3:WnX 0?T+m{ϩ+XdW]AW<(PW3îv$l+KhJ+wHs;J;+O?Hǫ*Rg+!B5EԵŭHEb?rA:J+^iMsR ,۴ L@ʙܺsǶRjx5RrgCQd/?Qr[ae}[MͿWC%X VI VO+_ڻ ѫux~[aa#"mq{>u|++Hf%V4`xRG8qq )lخt$҉:%OSq9+)i?|?TVLH`%]+`PVh^Bg%7Z`%>X+`D+;Vk Xi>s~؈Mw@WYT,JIĪpYA▻ocVt4+V6SW9+ٽJ^yVdGLχzVy+nVig=+0kf+qMawwP96J%#M?Yiv߷(YhӤWc<ofJD_a =+l^:<+zW&wx-A+ l(X/Q23!XzAH8eEBj[zK#VbD11GL`8_k붨ʸش}njxRb> ̈́Cm[(חSV+>. l(Ạ=3J|tEIEさaQCGG9}jdʊTGq ՄK -ۂyV XAm VJ¿D$\QK++ bz'0&@&*-EVTe$^$.Ԕm.?o{tFݘ3j43g&Ky<dus5B*X! X 0܍cEXA HuWO"\fvcXt3+JU w^NldXarpzR "plceR+s _y]bX+%V2x-*zn_Ն`Pwl2wR(*٨64 ͳrR SGb nf%Simo5NMs6>cwX_o:)tn"I2IhgmpY< V`KўbiQ8 Q}VI2OͽdH6w$#MZVXHV p;k\#pV$=Hʪ0gX˟# NFDj5)K9 8\Qι6F8H+z99?djԿy8UVZ+BJgEsm+yV0/6{0Iy @p")cEkcdX.?xt8.+lc^JY9+}ĵs̊Kn6ȳ5TXcg=K~dvε׳1Y1';I@""{Ha`T XyŜcX1V撱b+Ɗ2?|qfŻU]VOg+JۮM7_z^J&Vf0n$+0EQLQk$OhI%3V1ql_Ȥs,|ƍd:BSŗL"evf`eY9rH! $iX!qAK&2 ;#Эs(|ͫkH%p>ҜYh5 ,@SŗL"evf`YbVA) S[aXWT09rJZ܌|xK5+uJrAdt H>VMTcWS AFP ADZbRJ&+W) #!dy-od]X*?zE,]01o `qTŠk+]_ASOI4aHm l--(.cJK$פ0x\Ў[W2Vf{XiD5V:$ě$TKXij IƊUsKנI8Vq̝{Gwh Vʁ5??&+rf7.==],1dZ~0[n,+ʧg{Bpg|MkЖGm J!a?.a‚%({`%V V`+X V< nrV`{ߧ`e;2_tV.]wW}۽_S>W-Y)y-@tI}Qaerep#a" uj զb+bUBfycZENʪ mod) end end In this case `statement[1]` refers to a list of extra statements, the block we wish to parse. Note here that when parsing objects like modules and classes, we set the namespace for the duration of the block parsing by setting options on the `parse_block` method. ### API Differences for Legacy Handler Because the legacy handler uses the legacy parser and therefore a different kind of AST, there are subtle differences in the handler API. Most importantly, the `handles` method usually deals with either lexical tokens or source code as a string or RegExp object. The statement object, similarly, is made up of lexical tokens instead of semantically parsed nodes (this is described in the {file:docs/Parser.md parser document}). The module example above can be rewritten as a legacy handler as follows: class YARD::Handlers::Ruby::Legacy::ModuleHandler < YARD::Handlers::Ruby::Legacy::Base handles TkMODULE def process modname = statement.tokens.to_s[/^module\s+(#{NAMESPACEMATCH})/, 1] mod = register ModuleObject.new(namespace, modname) parse_block(:namespace => mod) end end A few notes on the differences: * We inherit from `Legacy::Base` instead of the standard Ruby Base handler class. * We exchange node type `:module` for `TkMODULE`, which represents the first token in the statement. * We perform direct string manipulation to get the module name. * `parse_block` does not take a list of statements. In the old parser API, each statement has a `block` attribute which defines the list of statements within that statement, if any. Therefore, `parse_block` will always parse the `statement.block` if it exists. yard-0.8.7.3/docs/GettingStarted.md0000644000004100000410000005346612261240652017076 0ustar www-datawww-data# @title Getting Started Guide # Getting Started with YARD There are a few ways which YARD can be of use to you or your project. This document will cover the most common ways to use YARD: * [Documenting Code with YARD](#docing) * [Using YARD to Generate Documentation](#using) * [Configuring YARD](#config) * [Extending YARD](#extending) * [Templating YARD](#templating) * [Plugin Support](#plugins) ## Documenting Code with YARD By default, YARD is compatible with the same RDoc syntax most Ruby developers are already familiar with. However, one of the biggest advantages of YARD is the extended meta-data syntax, commonly known as "tags", that you can use to express small bits of information in a structured and formal manner. While RDoc syntax expects you to describe your method in a completely free-form manner, YARD recommends declaring your parameters, return types, etc. with the `@tag` syntax, which makes outputting the documentation more consistent and easier to read. Consider the RDoc documentation for a method to_format: # Converts the object into textual markup given a specific `format` # (defaults to `:html`) # # == Parameters: # format:: # A Symbol declaring the format to convert the object to. This # can be `:text` or `:html`. # # == Returns: # A string representing the object in a specified # format. # def to_format(format = :html) # format the object end While this may seem easy enough to read and understand, it's hard for a machine to properly pull this data back out of our documentation. Also we've tied our markup to our content, and now our documentation becomes hard to maintain if we decide later to change our markup style (maybe we don't want the ":" suffix on our headers anymore). In YARD, we would simply define our method as: # Converts the object into textual markup given a specific format. # # @param format [Symbol] the format type, `:text` or `:html` # @return [String] the object converted into the expected format. def to_format(format = :html) # format the object end Using tags we can add semantic metadata to our code without worrying about presentation. YARD will handle presentation for us when we decide to generate documentation later. ## Which Markup Format? YARD does not impose a specific markup. The above example uses standard RDoc markup formatting, but YARD also supports textile and markdown via the command-line switch or `.yardopts` file (see below). This means that you are free to use whatever formatting you like. This guide is actually written using markdown. YARD, however, does add a few important syntaxes that are processed no matter which markup formatting you use, such as tag support and inter-document linking. These syntaxes are discussed below. ## Adding Tags to Documentation The tag syntax that YARD uses is the same @tag-style syntax you may have seen if you've ever coded in Java, Python, PHP, Objective-C or a myriad of other languages. The following tag adds an author tag to your class: # @author Loren Segal class MyClass end To allow for large amounts of text, the @tag syntax will recognize any indented lines following a tag as part of the tag data. For example: # @deprecated Use {#my_new_method} instead of this method because # it uses a library that is no longer supported in Ruby 1.9. # The new method accepts the same parameters. def mymethod end ### List of Tags A list of tags can be found in {file:docs/Tags.md#taglist} ### Reference Tags To reduce the amount of duplication in writing documentation for repetitive code, YARD introduces "reference tags", which are not quite tags, but not quite docstrings either. In a sense, they are tag (and docstring) modifiers. Basically, any docstring (or tag) that begins with "(see OTHEROBJECT)" will implicitly link the docstring or tag to the "OTHEROBJECT", copying any data from that docstring/tag into your current object. Consider the example: class MyWebServer # Handles a request # @param request [Request] the request object # @return [String] the resulting webpage def get(request) "hello" end # (see #get) def post(request) "hello" end end The above `#post` method takes the docstring and all tags (`param` and `return`) of the `#get` method. When you generate HTML documentation, you will see this duplication automatically, so you don't have to manually type it out. We can also add our own custom docstring information below the "see" reference, and whatever we write will be appended to the docstring: # (see #get) # @note This method may modify our application state! def post(request) self.state += 1; "hello" end Here we added another tag, but we could have also added plain text. The text must be appended *after* the `(see ...)` statement, preferably on a separate line. Note that we don't have to "refer" the whole docstring. We can also link individual tags instead. Since "get" and "post" actually have different descriptions, a more accurate example would be to only refer our parameter and return tags: class MyWebServer # Handles a GET request # @param request [Request] the request object # @return [String] the resulting webpage def get(request) "hello" end # Handles a POST request # @note This method may modify our application state! # @param (see #get) # @return (see #get) def post(request) self.state += 1; "hello" end end The above copies all of the param and return tags from `#get`. Note that you cannot copy individual tags of a specific type with this syntax. ## Declaring Types Some tags also have an optional "types" field which let us declare a list of types associated with the tag. For instance, a return tag can be declared with or without a types field. # @return [String, nil] the contents of our object or nil # if the object has not been filled with data. def validate; end # We don't care about the "type" here: # @return the object def to_obj; end The list of types is in the form `[type1, type2, ...]` and is mostly free-form, so we can also specify duck-types or constant values. For example: # @param argname [#to_s] any object that responds to `#to_s` # @param argname [true, false] only true or false Note the latter example can be replaced by the meta-type "Boolean". Another meta-type is "void", which stands for "no meaningful value" and is used for return values. These meta-types are by convention only, but are recommended. List types can be specified in the form `CollectionClass`. For instance, consider the following Array that holds a set of Strings and Symbols: # @param list [Array] the list of strings and symbols. We mentioned that these type fields are "mostly" free-form. In truth, they are defined "by convention". To view samples of common type specifications and recommended conventions for writing type specifications, see [http://yardoc.org/types.html](http://yardoc.org/types.html). Note that these conventions may change every now and then, although we are working on a more "formal" type specification proposal. ## Documenting DSL Methods Application code in Ruby often makes use of DSL style metaprogrammed methods. The most common is the `attr_accessor` method, which of course has built-in support in YARD. However, frameworks and libraries often expose custom methods that perform similar metaprogramming tasks, and it is often useful to document their functionality in your application. Consider the `property` method in a project like [DataMapper](http://datamapper.org), which creates a typed attribute for a database model. The code might look like: class Post include DataMapper::Resource property :title, String end As of version 0.7.0, YARD will automatically pick up on these basic methods if you document them with a docstring. Therefore, simply adding some comments to the code will cause it to generate documentation: class Post include DataMapper::Resource # @return [String] the title property of the post property :title, String end Note that YARD uses the first argument in the method call to determine the method name. In some cases, this would not be the method name, and you would need to declare it manually. You can do so with the `@!method` directive: # @!method foo create_a_foo_method The @!method directive can also accept a full method signature with parameters: # @!method foo(name, opts = {}) create_a_foo_method You can also set visibility and scope, or modify the method signature with extra tags. The following adds documentation for a private class method: # @!method foo(opts = {}) # The foo method! # @!scope class # @!visibility private create_a_private_foo_class_method Finally, you can tag a method as an attribute by replacing the @!method tag with @!attribute. The @!attribute directive allows for the flags [r], [w], or [rw] to declare a readonly, writeonly, or readwrite attribute, respectively. # @!attribute [w] # The writeonly foo attribute! a_writeonly_attribute :foo (Note that if the name can be automatically detected, you do not need to specify it in the @!method or @!attribute directives) However, you will notice a few drawbacks with this basic support: 1. There is a fair bit of duplication in such documentation. Specifically, we repeat the term String and title twice in the property example. 2. We must write a code comment for this property to show up in the documentation. If we do not write a comment, it is ignored. ### Macros Fortunately YARD 0.7.0 also adds macros, a powerful way to add support for these DSL methods on the fly without writing extra plugins. Macros allow you to interpolate arguments from the method call inside the docstring, reducing duplication. If we re-wrote the `property` example from above using a macro, it might look like: class Post include DataMapper::Resource # @!macro dm.property # @return [$2] the $1 $0 of the post property :title, String end (Note that $0 represents the method call, in this case `property`. The rest are arguments in the method call.) The above example is equivalent to the first version shown in the previous section. There is also some extra benefit to using this macro, in that we can re-apply it to any other property in our class by simply calling on the macro. The following: # @!macro dm.property property :view_count, Integer Would be equivalent to: # @return [Integer] the view_count property of the post property :view_count, Integer Finally, macros can be "attached" to method calls, allowing them to be implicitly activated every time the method call is seen in the source code of the class, or an inheriting class. By simply adding the `[attach]` flag, the macro becomes implicit on future calls. All of the properties below get documented by using this snippet: class Post include DataMapper::Resource # @!macro [attach] dm.property # @return [$2] the $1 $0 of the post property :title, String property :view_count, Integer property :email, String end You can read more about macros in the {file:docs/Tags.md Tags Overview} document. ## Customized YARD Markup YARD supports a special syntax to link to other code objects, URLs, files, or embed docstrings between documents. This syntax has the general form of `{Name OptionalTitle}` (where `OptionalTitle` can have spaces, but `Name` cannot). ### Linking Objects `{...}` To link another "object" (class, method, module, etc.), use the format: {ObjectName#method OPTIONAL_TITLE} {Class::CONSTANT My constant's title} {#method_inside_current_namespace} Without an explicit title, YARD will use the relative path to the object as the link name. Note that you can also use relative paths inside the object path to refer to an object inside the same namespace as your current docstring. Note that the `@see` tag automatically links its data. You should not use the link syntax in this tag: # @see #methodname <- Correct. # @see {#methodname} <- Incorrect. If you want to use a Hash, prefix the first { with "!": # !{ :some_key => 'value' } ### Linking URLs `{http://...}` URLs are also linked using this `{...}` syntax: {http://example.com Optional Title} {mailto:email@example.com} ### Linking Files `{file:...}` Files can also be linked using this same syntax but by adding the `file:` prefix to the object name. Files refer to extra readme files you added via the command-line. Consider the following examples: {file:docs/GettingStarted.md Getting Started} {file:mypage.html Name#anchor} As shown, you can also add an optional `#anchor` if the page is an HTML link. ### Embedding Docstrings `{include:...}` We saw the `(see ...)` syntax above, which allowed us to link an entire docstring with another. Sometimes, however, we just want to copy docstring text without tags. Using the same `{...}` syntax, but using the `include:` prefix, we can embed a docstring (minus tags) at a specific point in the text. # This class is cool # @abstract class Foo; end # This is another class. {include:Foo} too! class Bar; end The docstring for Bar becomes: "This is another class. This class is cool too!" ### Embedding Files `{include:file:...}` You can embed the contents of files using `{include:file:path/to/file}`, similar to the `{include:OBJECT}` tag above. If the file uses a specific markup type, it will be applied and embedded as marked up text. The following shows how the tag can be used inside of comments: # Here is an example of a highlighted Ruby file: # # {include:file:examples/test.rb} ### Rendering Objects `{render:...}` Entire objects can also be rendered in place in documentation. This can be used for guide-style documentation which does not document the entire source tree, but instead selectively renders important classes or methods. Consider the following documentation inside of a README file: !!!plain = igLatinPay! This library adds pig latin methods to the string class, allowing you to transform sentences into pig latin. {render:String#pig_latin} You can also un-pig-latin-ify a word or sentence: {render:String#de_pig_latin} The above would render the methods in place inside the README document, allowing you to summarize a small library in a single file. ## Using YARD to Generate Documentation ### `yard` Executable YARD ships with a single executable aptly named `yard`. In addition to generating standard documentation for your project, you would use this tool if you wanted to: * Document all installed gems * Run a local documentation server * Generate UML diagrams using [Graphviz][graphviz] * View `ri`-style documentation * Diff your documentation * Analyze documentation statistics. The following commands are available in YARD 0.6.x (see `yard help` for a full list): Usage: yard [options] Commands: config Views or edits current global configuration diff Returns the object diff of two gems or .yardoc files doc Generates documentation gems Builds YARD index for gems graph Graphs class diagram using Graphviz help Retrieves help for a command ri A tool to view documentation in the console like `ri` server Runs a local documentation server stats Prints documentation statistics on a set of files Note that `yardoc` is an alias for `yard doc`, and `yri` is an alias for `yard ri`. These commands are maintained for backwards compatibility. ### `.yardopts` Options File Unless your documentation is very small, you'll end up needing to run `yardoc` with many options. The `yardoc` tool will use the options found in this file. It is recommended to check this in to your repository and distribute it with your source. This file is placed at the root of your project (in the directory you run `yardoc` from) and contains all of arguments you would otherwise pass to the command-line tool. For instance, if you often type: yardoc --no-private --protected app/**/*.rb - README LEGAL COPYING You can place the following into your `.yardopts`: --no-private --protected app/**/*.rb - README LEGAL COPYING This way, you only need to type: yardoc Any extra switches passed to the command-line now will be appended to your `.yardopts` options. Note that options for `yardoc` are discussed in the {file:README.md README}, and a full overview of the `.yardopts` file can be found in {YARD::CLI::Yardoc}. ### Documenting Extra Files "Extra files" are extra guide style documents that help to give a brief overview of how to use your library/framework, as well as any extra information that might be vital for your users. The most common "extra file" is the README, which is automatically detected by YARD if found in the root of your project (any file starting with `README*`). You can specify extra files on the command line (or in the `.yardopts` file) by listing them after the '-' separator: yardoc lib/**/*.rb ext/**/*.c - LICENSE.txt Note that the README will automatically be picked up, so you do not need to specify it. If you don't want to modify the default file globs, you can ignore the first set of arguments: yardoc - LICENSE.txt Below you can read about how to customize the look of these extra files, both with markup and pretty titles. #### Adding Meta-Data to Extra Files You can add YARD-style `@tag` metadata to the top of any extra file if prefixed by a `#` hash comment. YARD allows for arbitrary meta-data, but pays special attention to the tags `@markup`, `@encoding`, and `@title`. Note that there cannot be any whitespace before the tags. Here is an example of some tag data in a README: # @markup markdown # @title The Best Library in the World! # @author The Author Name This is the best library you will ever meet. Lipsum ... The `@markup` tag allows you to specify a markup format to use for the file, including "markdown", "textile", "rdoc", "ruby", "text", "html", or "none" (no markup). This can be used when the markup cannot be auto-detected using the extension of the filename, if the file has no extension, or if you want to override the auto-detection. By using `@encoding` you can specify a non-standard encoding. Note that `yardoc --charset` sets the global encoding (for all comments / files), so if you are using unicode across all your files, you can specify it there. Using the `@encoding` tag might be used to override the default global charset, say, if you had a localized `README.jp` file with SJIS data. Also note that this only affects Ruby 1.9.x, as Ruby 1.8 is not properly encoding aware. The `@title` tag allows you to specify a full title name for the document. By default, YARD uses the filename as the title of the document and lists it in the file list in the index and file menu. In some cases, the file name might not be descriptive enough, so YARD allows you to specify a full title: contents of TITLE.txt: # @title The Title of The Document Currently all other meta-data is hidden from view, though accessible programmatically using the {YARD::CodeObjects::ExtraFileObject} class. ## Configuring YARD YARD (0.6.2+) supports a global configuration file stored in `~/.yard/config`. This file is stored as a YAML file and can contain arbitrary keys and values that can be used by YARD at run-time. YARD defines specific keys that are used to control various features, and they are listed in {YARD::Config::DEFAULT_CONFIG_OPTIONS}. A sample configuration file might look like: :load_plugins: false :ignored_plugins: - my_plugin - my_other_plugin :autoload_plugins: - my_autoload_plugin :safe_mode: false You can also view and edit these configuration options from the commandline using the `yard config` command. To list your configuration, use `yard config --list`. To view a key, use `yard config ITEM`, and to set it, use `yard config ITEM VALUE`. ## Extending YARD There are many ways to extend YARD to support non-standard Ruby syntax (DSLs), add new meta-data tags or programmatically access the intermediate metadata and documentation from code. An overview of YARD's full architecture can be found in the {file:docs/Overview.md} document. For information on adding support for Ruby DSLs, see the {file:docs/Handlers.md} and {file:docs/Parser.md} architecture documents. For information on adding extra tags, see {file:docs/Tags.md}. For information on accessing the data YARD stores about your documentation, look at the {file:docs/CodeObjects.md} architecture document. ## Templating YARD In many cases you may want to change the style of YARD's templates or add extra information after extending it. The {file:docs/Templates.md} architecture document covers the basics of how YARD's templating system works. ## Plugin Support As of 0.4, YARD will automatically load any gem named with the prefix of `yard-` or `yard_`. You can use this to load a custom plugin that [extend](#extending) YARD's functionality. A good example of this is the [yard-rspec][yard-rspec] plugin, which adds [RSpec][rspec] specifications to your documentation (`yardoc` and `yri`). You can try it out by installing the gem or cloning the project and trying the example: $ gem install yard-rspec -s http://gemcutter.org or $ git clone git://github.com/lsegal/yard-spec-plugin YARD also provides a way to temporarily disable plugins on a per-user basis. To disable a plugin create the file `~/.yard/ignored_plugins` with a list of plugin names separated by newlines. Note that the `.yard` directory might not exist, so you may need to create it. [graphviz]:http://www.graphviz.org [yard-rspec]:http://github.com/lsegal/yard-spec-plugin [rspec]:http://rspec.info yard-0.8.7.3/docs/TagsArch.md0000644000004100000410000001114412261240652015625 0ustar www-datawww-data# @title Tags Architecture # Tags Architecture ## Programmatic API ### Accessing Tag Information Tag metadata is added when a {YARD::Docstring} is added to a {file:docs/CodeObjects.md code object} using the {YARD::CodeObjects::Base#docstring=} attribute. In addition to adding conventional comments, tags are parsed and associated with the object. The easiest way to access tags on an object is to use the {YARD::CodeObjects::Base#tag} and `#tags` methods, for example: # Using the Foo class object from above obj.tags(:tagname).first.text #=> "some data" Because multiple tags can be stored with the same name, they are stored as a list of tags. The `#tag` method is an alias for the first item in the list of tags. Also note that the `#tag`, `#tags` and `#has_tag?` methods are all convenience methods that delegate to the {YARD::Docstring} object described above. ### Adding Custom Tags The `@tagname` tag used in the above examples is clearly not part of the tags that come with YARD. If such a tag would actually be part of documentation under a default install, YARD would raise a warning that the tag does not exist. It is, however, trivial to add this tag to be recognized by YARD. All tags in YARD are added to the {YARD::Tags::Library tag library} which makes use of a tag factory class to parse the data inside the tags. To simply add a tag that stores simple text like our `@tagname` tag above, use: YARD::Tags::Library.define_tag("A Sample Tag", :tagname) This will now allow YARD to add the metadata from `@tagname` to the docstring. ## Tag Factory Architecture Recognizing a tag is one part of the process. Parsing the tag contents is the second step. YARD has a tag architecture that allows developers to add or completely change the way tags contents can be parsed. The separation of registration and tag creation can be seen in the following class diagram: ![Tags Architecture Class Diagram](images/tags-class-diagram.png) ### DefaultFactory By default, YARD has a few standard syntaxes that can be parsed for tags. These are all implemented by the {YARD::Tags::DefaultFactory} class. These syntaxes are: * Standard text: no parsing is done, but text is stripped of newlines and multiple spaces. * Raw text: does no parsing at all, no stripping of newlines or spaces. This is best used for code snippets. * Raw text with title: does no parsing on the text but extracts the first line of the metadata as the "title", useful for tags such as `@example`: # @example Inspect an element # myobj.inspect #=> # * Text with types: parses a list of types at the beginning of the text. Types are optional. The standard syntax is in the form `[type1, type2, ...]`, for example: # @return [String, Symbol] a description here # @return description here with no types * Text with types and a name: parses a list of types at the beginning of text followed by a name and extra descriptive text. For example: # @param [String] str the string to reverse def reverse(str) '...' end As mentioned above, this syntax is implemented by the `DefaultFactory` which can be swapped out for any factory. In some cases, a developer may want to change the type declaration syntax to be in the form: # @tagname name description This can be done by simply implementing a new factory that parses the data in this form. ### Implementing a Factory Factories should implement the method `parse_tag` as well as any `parse_tag_SUFFIX` method where SUFFIX refers to the suffix added when declaring the tag. For example, a tag can also be declared as follows: YARD::Tags::Library.define_tag "Parameter", :param, :with_types In such a case, the factory will be called with method `parse_tag_with_types`. In all cases, the method should return a new {YARD::Tags::Tag} object. Generally, the `parse_tag` methods take 2 or 3 parameters. A simple tag can be implemented as: def parse_tag(tag_name, text) Tag.new(tag_name, text) end The text parameter contains pre-parsed text with extra spaces and newlines removed. If required, the method could also be declared with a third parameter containing unmodified raw text: def parse_tag_with_raw_text(tag_name, text, raw_text) Tag.new(tag_name, raw_text) end Note that this method would be invoked for a tag declared with the `:with_raw_text` suffix. ### Changing the Factory To change the factory, set the {YARD::Tags::Library.default_factory} attribute: YARD::Tags::Library.default_factory = MyFactory This must be done before any parsing is done, or the factory will not be used. yard-0.8.7.3/docs/templates/0000755000004100000410000000000012261240652015604 5ustar www-datawww-datayard-0.8.7.3/docs/templates/default/0000755000004100000410000000000012261240652017230 5ustar www-datawww-datayard-0.8.7.3/docs/templates/default/yard_tags/0000755000004100000410000000000012261240652021205 5ustar www-datawww-datayard-0.8.7.3/docs/templates/default/yard_tags/html/0000755000004100000410000000000012261240652022151 5ustar www-datawww-datayard-0.8.7.3/docs/templates/default/yard_tags/html/setup.rb0000644000004100000410000000121012261240652023630 0ustar www-datawww-datadef init sections :list, [T('docstring')] end def tag_signature(tag) types = tag.types || [] signature = "#{tag_link_name(tag)} " extra = nil if sig_tag = tag.object.tag('yard.signature') extra = sig_tag.text end extra = case types.first when 'with_name' "name description" when 'with_types' "[Types] description" when 'with_types_and_name' "name [Types] description" when 'with_title_and_text' "title\ndescription" when 'with_types_and_title' "[Types] title\ndescription" else "description" end if extra.nil? signature + h(extra).gsub(/\n/, "
               ") endyard-0.8.7.3/docs/templates/default/yard_tags/html/list.erb0000644000004100000410000000100412261240652023611 0ustar www-datawww-data<% [["Tag", all_tags], ["Directive", all_directives]].each do |(name, list)| %>

            <%= name %> List

            <% list.each_with_index do |tag, i| %>

            <%= tag_signature tag %>

            <% if name == "Directive" %> <%= yieldall :object => P("YARD::Tags::#{tag.text}") %> <% else %> <%= yieldall :object => tag.object %> <% end %>
            <% end %> <% end%> yard-0.8.7.3/docs/templates/default/layout/0000755000004100000410000000000012261240652020545 5ustar www-datawww-datayard-0.8.7.3/docs/templates/default/layout/html/0000755000004100000410000000000012261240652021511 5ustar www-datawww-datayard-0.8.7.3/docs/templates/default/layout/html/setup.rb0000644000004100000410000000024312261240652023175 0ustar www-datawww-datadef init super sections.place(:tag_list).after_any(:files) end def menu_lists super + [{:type => 'tag', :title => 'Tags', :search_title => 'Tag List'}] end yard-0.8.7.3/docs/templates/default/layout/html/tag_list.erb0000644000004100000410000000060712261240652024014 0ustar www-datawww-data

            Tag Listing

            The following are a brief list of tags that can be used in YARD formatted documentation. See <%= link_file "docs/Tags.md" %> for information on using tags.

              <% n = 1 %> <% collect_tags.each do |tag| %>
            • <%= tag_link(tag) %>
            • <% n = n == 2 ? 1 : 2 %> <% end %>
            yard-0.8.7.3/docs/templates/default/fulldoc/0000755000004100000410000000000012261240652020660 5ustar www-datawww-datayard-0.8.7.3/docs/templates/default/fulldoc/html/0000755000004100000410000000000012261240652021624 5ustar www-datawww-datayard-0.8.7.3/docs/templates/default/fulldoc/html/full_list_tag.erb0000644000004100000410000000035012261240652025144 0ustar www-datawww-data<% n = 1 %> <% collect_tags.each do |tag| %>
          • <%= tag_link(tag) %>
          • <% n = n == 2 ? 1 : 2 %> <% end %>yard-0.8.7.3/docs/templates/default/fulldoc/html/setup.rb0000644000004100000410000000016512261240652023313 0ustar www-datawww-datadef generate_tag_list @list_title = "Tag List" @list_type = "tag" asset('tag_list.html', erb(:full_list)) end yard-0.8.7.3/docs/templates/plugin.rb0000644000004100000410000000331112261240652017425 0ustar www-datawww-datainclude YARD include Templates module TagTemplateHelper def all_tags Registry.all(:method).map {|m| m.tag('yard.tag') }.compact end def all_directives Registry.all(:method).map {|m| m.tag('yard.directive') }.compact end def collect_tags (all_tags + all_directives).sort_by {|t| t.name } end def tag_link(tag) link_file("docs/Tags.md", tag_link_name(tag), tag.name) end def tag_link_name(tag) prefix = tag.tag_name == 'yard.directive' ? '@!' : '@' h(prefix + tag.name) end # Wrap url_for and url_for_file to rewrite object when generating docs for # yard.tag/directive objects. %w(url_for, url_for_file).each do |meth| self.class.send(:define_method, meth) do if object.is_a?(CodeObjects::Base) && (object.tag('yard.tag') || object.tag('yard.directive') || (object.type == :class && object.superclass.name == :Directive)) obj, self.object = object, Registry.root url = super self.object = obj url else super end end end def linkify(*args) if args.first.is_a?(String) case args.first when "yard:include_tags" return T('yard_tags').run(options) when /^tag:(\S+)/ tag_name, suffix = $1, "tag" if tag_name =~ /^!/ tag_name, suffix = tag_name[1..-1], "directive" end if obj = Registry.at("YARD::Tags::Library##{tag_name}_#{suffix}") return tag_link(obj.tag("yard.#{suffix}")) end log.warn "Cannot find tag: #{args.first}" return args.first end end super end end Template.extra_includes << TagTemplateHelper Engine.register_template_path(File.dirname(__FILE__)) yard-0.8.7.3/docs/Tags.md0000644000004100000410000003224312261240652015032 0ustar www-datawww-data# @title Tags Overview # Tags Overview Tags represent meta-data as well as behavioural data that can be added to documentation through the `@tag` style syntax. As mentioned, there are two basic types of tags in YARD, "meta-data tags" and "behavioural tags", the latter is more often known as "directives". These two tag types can be visually identified by their prefix. Meta-data tags have a `@` prefix, while directives have a prefix of `@!` to indicate that the directive performs some potentially mutable action on or with the docstring. The two tag types would be used in the following way, respectively: # @meta_data_tag some data # @!directive_tag some data class Foo; end This document describes how tags can be specified, how they affect your documentation, and how to use specific built-in tags in YARD, as well as how to define custom tags. ## Meta-Data Tags Meta-data tags are useful to add arbitrary meta-data about a documented object. These tags simply add data to objects that can be looked up later, either programmatically, or displayed in templates. The benefit to describing objects using meta-data tags is that your documentation can be organized semantically. Rather than having a huge listing of text with no distinction of what each paragraph is discussing, tags allow you to focus in on specific elements of your documentation. For example, describing parameters of a method can often be important to your documentation, but should not be mixed up with the documentation that describes what the method itself does. In this case, separating the parameter documentation into {tag:param} tags can yield much better organized documentation, both in source and in your output, without having to manually format the data using standard markup. All of this meta-data can be easily parsed by tools and used both in your templates as well as in code checker tools. An example of how you can leverage tags programmatically is shown in the {tag:todo} tag, which lists a small snippet of Ruby code that can list all of your TODO items, if they are properly tagged. Custom meta-data tags can be added either programmatically or via the YARD command-line. This is discussed in the "[Adding Custom Tags](#Adding_Custom_Tags)" section. A list of built-in meta-data tags are found below in the [Tag List](#Tag_List). ## Directives Directives are similar to meta-data tags in the way they are specified, but they do not add meta-data to the object directly. Instead, they affect the parsing context and objects themselves, allowing a developer to create objects (like methods) outright, rather than simply add text to an existing object. Directives have a `@!` prefix to differentiate these tags from meta-data tags, as well as to indicate that the tag may modify or create new objects when it is called. A list of built-in directives are found below in the [Directive List](#Directive_List). ## Tag Syntax Tags begin with the `@` or `@!` prefix at the start of a comment line, followed immediately by the tag name, and then optional tag data (if the tag requires it). Unless otherwise specified by documentation for the tag, all "description" text is considered free-form data and can include any arbitrary textual data. ### Multi-line Tags Tags can span multiple lines if the subsequent lines are indented by more than one space. The typical convention is to indent subsequent lines by 2 spaces. In the following example, `@tagname` will have the text *"This is indented tag data"*: # @tagname This is # indented tag data # but this is not For most tags, newlines and indented data are not significant and do not impact the result of the tag. In other words, you can decide to span a tag onto multiple lines at any point by creating an indented block. However, some tags like {tag:example}, {tag:overload}, {tag:!macro}, {tag:!method}, and {tag:!attribute} rely on the first line for special information about the tag, and you cannot split this first line up. For instance, the {tag:example} tag uses the first line to indicate the example's title. ### Common Tag Syntaxes Although custom tags can be parsed in any way, the built-in tags follow a few common syntax structures by convention in order to simplify the syntax. The following syntaxes are available: 1. **Freeform data** — In this case, any amount of textual data is allowed, including no data. In some cases, no data is necessary for the tag. 2. **Freeform data with a types specifier list** — Mostly freeform data beginning with an *optional* types specifier list surrounded in `[brackets]`. Note that for extensibility, other bracket types are allowed, such as `<>`, `()` and `{}`. The contents of the list are discussed in detail below. 3. **Freeform data with a name and types specifier list** — freeform data beginning with an *optional* types list, as well as a name key. The name key is *required*. Note that for extensibility, the name can be placed *before* the types list, like: `name [Types] description`. In this case, a separating space is not required between the name and types, and you can still use any of the other brackets that the type specifier list allows. 4. **Freeform data with title** — freeform data where the first line cannot be split into multiple lines. The first line must also always refer to the "title" portion, and therefore, if there is no title, the first line must be blank. The "title" might occasionally be listed by another name in tag documentation, however, you can identify this syntax by the existence of a multi-line signature with "Indented block" on the second line. In the tag list below, the term "description" implies freeform data, `[Types]` implies a types specifier list, "name" implies a name key, and "title" implies the first line is a newline significant field that cannot be split into multiple lines. ### Types Specifier List In some cases, a tag will allow for a "types specifier list"; this will be evident from the use of the `[Types]` syntax in the tag signature. A types specifier list is a comma separated list of types, most often classes or modules, but occasionally literals. For example, the following {tag:return} tag lists a set of types returned by a method: # Finds an object or list of objects in the db using a query # @return [String, Array, nil] the object or objects to # find in the database. Can be nil. def find(query) finder_code_here end A list of conventions for type names is specified below. Typically, however, any Ruby literal or class/module is allowed here. Duck-types (method names prefixed with "#") are also allowed. Note that the type specifier list is always an optional field and can be omitted when present in a tag signature. This is the reason why it is surrounded by brackets. It is also a freeform list, and can contain any list of values, though a set of conventions for how to list types is described below. ### Type List Conventions

            A list of examples of common type listings and what they translate into is available at http://yardoc.org/types.

            Typically, a type list contains a list of classes or modules that are associated with the tag. In some cases, however, certain special values are allowed or required to be listed. This section discusses the syntax for specifying Ruby types inside of type specifier lists, as well as the other non-Ruby types that are accepted by convention in these lists. It's important to realize that the conventions listed here may not always adequately describe every type signature, and is not meant to be a complete syntax. This is why the types specifier list is freeform and can contain any set of values. The conventions defined here are only conventions, and if they do not work for your type specifications, you can define your own appropriate conventions. Note that a types specifier list might also be used for non-Type values. In this case, the tag documentation will describe what values are allowed within the type specifier list. #### Class or Module Types Any Ruby type is allowed as a class or module type. Such a type is simply the name of the class or module. Note that one extra type that is accepted by convention is the `Boolean` type, which represents both the `TrueClass` and `FalseClass` types. This type does not exist in Ruby, however. #### Parametrized Types In addition to basic types (like String or Array), YARD conventions allow for a "generics" like syntax to specify container objects or other parametrized types. The syntax is `Type`. For instance, an Array might contain only String objects, in which case the type specification would be `Array`. Multiple parametrized types can be listed, separated by commas. Note that parametrized types are typically not order-dependent, in other words, a list of parametrized types can occur in any order inside of a type. An array specified as `Array` can contain any amount of Strings or Fixnums, in any order. When the order matters, use "order-dependent lists", described below. #### Duck-Types Duck-types are allowed in type specifier lists, and are identified by method names beginning with the "#" prefix. Typically, duck-types are recommended for {tag:param} tags only, though they can be used in other tags if needed. The following example shows a method that takes a parameter of any type that responds to the "read" method: # Reads from any I/O object. # @param [#read] io the input object to read from def read(io) io.read end #### Hashes Hashes can be specified either via the parametrized type discussed above, in the form `Hash`, or using the hash specific syntax: `Hash{KeyTypes=>ValueTypes}`. In the latter case, KeyTypes or ValueTypes can also be a list of types separated by commas. #### Order-Dependent Lists An order dependent list is a set of types surrounded by "()" and separated by commas. This list must contain exactly those types in exactly the order specified. For instance, an Array containing a String, Fixnum and Hash in that order (and having exactly those 3 elements) would be listed as: `Array<(String, Fixnum, Hash)>`. #### Literals Some literals are accepted by virtue of being Ruby literals, but also by YARD conventions. Here is a non-exhaustive list of certain accepted literal values: * `true`, `false`, `nil` — used when a method returns these explicit literal values. Note that if your method returns both `true` or `false`, you should use the `Boolean` conventional type instead. * `self` — has the same meaning as Ruby's "self" keyword in the context of parameters or return types. Recommended mostly for {tag:return} tags that are chainable. * `void` — indicates that the type for this tag is explicitly undefined. Mostly used to specify {tag:return} tags that do not care about their return value. Using a `void` return tag is recommended over no type, because it makes the documentation more explicit about what the user should expect. YARD will also add a note for the user if they have undefined return types, making things clear that they should not use the return value of such a method. ### Reference Tags

            Reference tag syntax applies only to meta-data tags, not directives.

            If a tag's data begins with `(see OBJECT)` it is considered a "reference tag". A reference tag literally copies the tag data by the given tag name from the specified OBJECT. For instance, a method may copy all {tag:param} tags from a given object using the reference tag syntax: # @param [String] user the username for the operation # @param [String] host the host that this user is associated with # @param [Time] time the time that this operation took place def clean(user, host, time = Time.now) end # @param (see #clean) def activate(user, host, time = Time.now) end ## Adding Custom Tags

            If a tag is specific to a given project, consider namespacing it by naming it in the form projectname.tagname, ie., yard.tag_signature.

            Custom tags can be added to YARD either via the command-line or programmatically. The programmatic method is not discussed in this document, but rather in the {file:docs/TagsArch.md} document. To add a custom tag via the command-line or .yardopts file, you can use the `--*-tag` options. A few different options are available for the common tag syntaxes described above. For example, to add a basic freeform tag, use: !!!sh $ yard doc --tag rest_url:"REST URL" This will register the `@rest_url` tag for use in your documentation and display this tag in HTML output wherever it is used with the heading "REST URL". Note that the tag title should follow the tag name with a colon (`:`). Other tag syntaxes exist, such as the type specifier list freeform tag (`--type-tag`), or a named key tag with types (`--type-name-tag`). If you want to create a tag but not display it in output (it is only for programmatic use), add `--hide-tag tagname` after the definition: !!!sh $ yard doc --tag complexity:"McCabe Complexity" --hide-tag complexity Note that you might not need a tag title if you are hiding it. The title part can be omitted. {yard:include_tags} yard-0.8.7.3/docs/Overview.md0000644000004100000410000000502512261240652015740 0ustar www-datawww-data# @title Architecture Overview # Architecture Overview YARD is separated in three major components, each of which allows YARD to be extended for a separate purpose. The split also emphasizes YARD's design choice to explicitly separate data gathering from HTML document generation, something that tools like RDoc do not do. These components are: * [Code Parsing & Processing Component](#parsing) * [Data Storage Component](#storage) * [Post Processing & Templating System](#templates) This separation is a major goal of the project, and means that YARD is not *just* a tool to generate HTML output. The expectation is that any subset of YARD's major components may be used, extended or modified independently. YARD may be used just as a data gathering tool (to parse and audit code), just as a data source (a webserver containing raw unformatted data about code), or just as a conventional HTML documentation generation tool (like RDoc). The important classes and dependencies of these components are shown in the following class diagram: ![Overview Class Diagram](images/overview-class-diagram.png) ## Code Parsing & Processing Component This component is made up of four sub-components, each of which have separate tasks during the data gathering process (*note: the tag architecture is not* *shown in the class diagram*). These sub-components are: * {file:docs/Parser.md} * {file:docs/Handlers.md} * {file:docs/CodeObjects.md} * {file:docs/Tags.md} The parser component reads source files and converts it into a set of statements which the handlers then process, creating code objects which in turn create tags (meta-data) attached to the objects. These objects are all added to the {YARD::Registry}, the data store component. ## Data Storage Component This component is currently implemented as a simple Ruby marshalled flat namespace of object. The implementation is found in the single class {YARD::Registry}, which is the centralized repository for all data being parsed, stored and accessed. There are future plans to improve this storage mechanism to be backend agnostic and allow for more robust storage. ## Post Processing & Templating System This component handles processing of objects from the registry through a templating engine that allows output to a variety of formats. Practically speaking, this is where templates can be implemented to change the design, output or structure of the data. See {file:docs/Templates.md Templates Architecture} for a complete overview. yard-0.8.7.3/docs/Parser.md0000644000004100000410000002125112261240652015365 0ustar www-datawww-data# @title Parser Architecture # Parser Architecture The parser component of YARD is the first component in the data processing pipeline that runs before any handling is done on the source. The parser is meant to translate the source into a set of statements that can be understood by the {file:docs/Handlers.md Handlers} that run immediately afterwards. The important classes are described in the class diagram of the entire parser system below: ![Parser Class Diagram](images/parser-class-diagram.png) (Note: the RubyToken classes are omitted from the diagram) ## SourceParser The main class {YARD::Parser::SourceParser} acts as a factory class, instantiating the correct parser class, an implementation of {YARD::Parser::Base}. The selected parser is chosen based on either the file extension or by selecting it explicitly (as an argument to parsing methods). YARD supports Ruby and C source files, but custom parsers can be implemented and registered for various other languages by subclassing `Parser::Base` and registering the parser with {YARD::Parser::SourceParser.register_parser_type}. This factory class should always be used when parsing source files rather than the individual parser classes since it initiates the pipeline that runs the handlers on the parsed source. The parser used must also match the handlers, and this is coordinated by the `SourceParser` class as well. ## Using the SourceParser Class The `SourceParser` class API is optimized for parsing globs of files. As such, the main method to use the class is the `parse` class method, which takes an array of file globs or a single file glob. YARD::Parser::SourceParser.parse('spec_*.rb') YARD::Parser::SourceParser.parse(['spec_*.rb', '*_helper.rb']) This is equivalent to the convenience method {YARD.parse}: YARD.parse('lib/**/*.rb') In some cases (ie. for testing), it may be more helpful to parse a string of input directly. In such a case, the method {YARD::Parser::SourceParser.parse_string} should be used: YARD::Parser::SourceParser.parse_string("def method(a, b) end") You can also provide the parser type explicitly as the second argument: # Parses a string of C YARD::Parser::SourceParser.parse_string("int main() { }", :c) Note that these two methods are aliased as {YARD.parse} and {YARD.parse_string} for convenience. ## Implementing and Registering a Custom Parser To implement a custom parser, subclass {YARD::Parser::Base}. Documentation on which abstract methods should be implemented are documented in that class. After the class is implemented, it is registered with the {YARD::Parser::SourceParser} factory class to be called when a file of the right extension needs to be parsed, or when a user selects that parser type explicitly. To register your new parser class, call the method {YARD::Parser::SourceParser.register_parser_type}: SourceParser.register_parser_type(:my_parser, MyParser, 'my_parser_ext') The last argument can be a single extension, a list of extensions (Array), a single Regexp, or a list of Regexps. Do not include the '.' in the extension. ## The Two Ruby Parser Types When parsing Ruby, the SourceParser can either instantiate the new {YARD::Parser::Ruby::RubyParser} class or the {YARD::Parser::Ruby::Legacy::StatementList} class. The first of the two, although faster, more robust and more efficient, is only available for Ruby 1.9. The legacy parser parser is available in both 1.8.x and 1.9, if compatibility is required. The choice of parser will affect which handlers ultimately get used, since new handlers can only use the new parser and the same requirement applies to the legacy parser & handlers. ## Switching to Legacy Parser By default, running YARD under Ruby 1.9 will automatically select the new parser and new handlers by extension. Although YARD supports both handler styles, plugins may choose to only implement one of the two (though this is not recommended). If only the legacy handlers are implemented, the `SourceParser` class should force the use of the legacy parser by setting the `parser_type` attribute as such: YARD::Parser::SourceParser.parser_type = :ruby18 The default value is `:ruby`. Note that this cannot be forced the other way around, a parser type of `:ruby` cannot be set under Ruby 1.8.x as the new parser is not supported under 1.8. ## RubyParser (the New Parser) The new Ruby parser uses the Ripper library that is packaged as part of stdlib in Ruby 1.9. Because of this, it can generate an AST from a string of Ruby input that is similar to the style of other sexp libraries (such as ParseTree). Each node generated in the tree is of the base type {YARD::Parser::Ruby::AstNode}, which has some subclasses for common node types. ### AstNode Basics The `AstNode` class behaves like a standard Array class in which all of its data make up the list of elements in the array. Unlike other sexp style libraries, however, the node type is not the first element of the list. Instead, the node type is defined by the `#type` method. The following examples show some of the basic uses of `AstNode`: # The sexp defines the statement `hello if 1` node = s(:if_mod, s(:int, "1"), s(:var_ref, s(:ident, "hello"))) node.type #=> :if_mod node[0] #=> s(:int, "1") node[0][0] #=> "1" (Note the `s()` syntax is shorthand for `AstNode.new(...)`. `s()` with no type is shorthand for a node of type `:list`) As shown, not all of the elements are AstNodes in themselves, some are String objects containing values. A list of only the AstNodes within a node can be accessed via the {YARD::Parser::Ruby::AstNode#children #children} method. Using the sexp declared above, we can do: node.children #=> [s(:int, "1"), s(:var_ref, s(:ident, "hello"))] ### AstNode#source and #line Every node defines the `#source` method which returns the source code that the node represents. One of the most common things to do with a node is to grab its source. The following example shows how this can be done: source = "if 1 == 1 then\n raise Exception\n end" ast = YARD::Parser::Ruby::RubyParser.parse(source).root ast[0].condition.source #=> "1 == 1" ast[0].then_block.source #=> "raise Exception" Note that this only works on source parsed from the RubyParser, not sexps declared using the `s()` syntax. This is because no source code is generated or stored by nodes. Instead, only the character ranges are stored, which are then looked up in the original full source string object. For example: # Following the code snippet above ast[0].then_block.source_range #=> 17..31 We can also get the line and line ranges in a similar fashion: ast[0].type #=> :if ast[0].line #=> 1 ast[0].line_range #=> 1..3 (note the newlines in the source) ### AstNode#jump Often the AST will be such that the node we care about might be buried arbitrarily deep in a node's hierarchy. The {YARD::Parser::Ruby::AstNode#jump} method exists to quickly get at a node of a specific type in such a situation: # Get the first identifier in the statement ast = s(s(:int, "1"), s(s(:var_ref, s(:ident, "hello")))) ast.jump(:ident)[0] #=> "hello" Multiple types can be searched for at once. If none are found, the original root node is returned so that it may be chained. ## The Legacy Parser The goal of the legacy parser is much the same as the new parser, but it is far more simplistic. Instead of a full-blown AST, the legacy parser simply groups together lists of "statements" called a {YARD::Parser::Ruby::Legacy::StatementList}. These statement lists are made up of {YARD::Parser::Ruby::Legacy::Statement} objects. A statement is any method call condition, loop, or declaration. Each statement may or may not have a block. In the case of a condition or loop, the block is the inner list of statements; in the case of a method call, the block is a do block (if provided). The statements themselves are made up of tokens, so instead of being semantic in nature like the new parser, statements are tied directly to the lexical tokens that make them up. To convert a statement into source, you simply join all the tokens together (this is done through the use of `#to_s`). Note that because there is little semantic parsing, the legacy parser is less able to deal with certain Ruby syntaxes. Specifically, the `:if_mod` syntax seen above ("hello if 1") would be considered two statements with the new parser, but using the legacy parser it is only one statement: stmts = ARD::Parser::Ruby::Legacy::StatementList.new("hello if 1") stmts[0].block #=> nil stmts[0].tokens.to_s #=> "hello if 1" In addition, this means that most handling still needs to be done via string manipulation and regular expression matching, making it considerably more difficult to use in edge case scenarios. yard-0.8.7.3/docs/WhatsNew.md0000644000004100000410000015135512261240652015702 0ustar www-datawww-data# @title What's New? # What's New in 0.8.x? 1. **Directives (new behavioural tag syntax)** (0.8.0) 2. **Added `--embed-mixin(s)` to embed mixins into class docs** (0.8.0) 3. **Internationalization (I18n) support for translating docs** (0.8.0) 4. **New C parser / handlers architecture** (0.8.0) 5. **YARD will now warn if `@param` name not in method params** (0.8.0) 6. **Added support for `module_function` calls in Ruby code** (0.8.0) 7. **Greatly improved tag documentation using custom template** (0.8.0) 8. **Tags can now contain '.' for namespacing** (0.8.0) 9. **Added "frames" links for non-framed pages for better nav** (0.8.0) 10. **Added Gemfile support to YARD server for local gem sets** (0.8.0) 11. **Server now displays README on index route like static docs** (0.8.0) 12. **Added line numbers to `yard stats --list-undoc --compact`** (0.8.0) 13. **Single object db now default (multi-object db unsupported)** (0.8.0) 14. **Added `--api` tag to generate documentation for API sets** (0.8.1) 15. **Added `--non-transitive-tag` to disable transitive tag** (0.8.3) 16. **Added `-B/--bind` to bind to a port in yard server** (0.8.4) 17. **Added `asciidoc` markup type support** (0.8.6) 18. **Added `yard markups` command to list available markup types** (0.8.6) 19. **Added `yard display` command to display formatted objects** (0.8.6) 20. **Added `--layout` to `yard display` command** (0.8.6.1) ## Directives (new behavioural tag syntax) (0.8.0)

            The tags {tag:!macro}, {tag:!method}, {tag:!attribute}, {tag:!group}, {tag:!endgroup}, {tag:!scope} and {tag:!visibility} have been changed from meta-data tags to directives. This means they should now be called with the "@!" prefix instead of "@". Note however that for backward compatibility, the old "@macro", "@method", etc., syntax for all of these tags will still work and is supported.

            Some backwards incompatible changes were made to {tag:!macro} syntax. Please read this section carefully if you are using this tag.

            YARD 0.8.0 adds a new tag syntax called "directives" using the `@!` prefix. These directive tags can be used to modify parser state while processing objects, or even create new objects on the fly. A plugin API is available similar to tags, and directives should be registered in the {YARD::Tags::Library} class using {YARD::Tags::Library.define_directive}. To use a directive, simply call it the same way as any tag. Tag syntax is documented in {file:docs/Tags.md}. ### Notable features of directives #### Directives do not need to be attached to object docstrings Unlike meta-data tags which apply to created objects, directives do not need to be attached to an object in order to be used. This means you can have free-standing comments with directives, such as: # @macro mymacro # A new macro, not attached to any docstring # ...other Ruby code here... # Using the macro: # @macro mymacro def mymethod; end You can do the same to define methods and attributes, as discussed below. #### `@!method` and `@!attribute` directives improved The method and attribute directives can now be used to create multiple objects in a single docstring. Previously a `@method` or `@attribute` tag would only create one method per docstring. In 0.8.0, you could attach multiple methods to the same block of Ruby source, such as: # @!method foo(a, b, c) # @!method bar(x, y, z) # Docstring for code some_ruby_source The above creates #foo and #bar and the source listing for both will be `some_ruby_source` with "Docstring for code" as the docstring. The attribute directive can take advantage of this functionality as well. Note that these directives also do not need to be attached to a line of code to be recognized; they can be in free-standing comments if the methods are defined dynamically and not associated with any code. #### New `@!parse` directive to parse Ruby code A new {tag:!parse} directive was added that allows a developer to have YARD parse code that might not necessarily be parseable in its original form. This is useful when using `instance_eval` and other dynamic meta-programming techniques to define methods or perform functionality. For instance, a common case of the "self.included" callback in module to extend a module on a class might be in the form: def self.included(mod) mod.extend(self) end Unfortunately, this does not get picked up by YARD, but on the original class, we can add: class MyClass # @!parse extend TheDynamicModule include TheDynamicModule end YARD will then parse the code `extend TheDynamicModule` as if it were in the source file. You can also use this technique to register regular methods as attributes, if you did not define them with `attr_*` methods: def foo; @foo end def foo=(v) @foo = v end # Register them as methods: # @!parse attr_accessor :foo ### Backward incompatible changes to `@!macro` directive Unfortunately, in order to create the new directives architecture, some previously supported syntax in `@macro` tags are no longer supported. Specifically, macros can no longer expand text on an entire docstring. Instead, macros only expand the data that is indented inside of the tag text. This syntax is **no longer supported**: # @macro mymacro # Expanding text $1 $2 $3 property :a, :b, :c In 0.7.0 to 0.7.5, the above would have created a method with the docstring "Expanding text a b c". This will not work in 0.8.0. Instead, you must indent all the macro expansion data so that it is part of the `@macro` tag as follows: # @!macro mymacro # Expanding text $1 $2 $3 property :a, :b, :c Note that we also use the recommended `@!macro` syntax, though `@macro` is still supported. ## Added `--embed-mixin(s)` to embed mixins into class docs (0.8.0) Methods from mixins can now be embedded directly into the documentation output for a class by using `--embed-mixin ModuleName`, or `--embed-mixins` for all mixins. This enables a documentation writer to refactor methods into modules without worrying about them showing up in separate files in generated documentation. When mixin methods are embedded, they show up in both the original module page and the pages of the classes they are mixed into. A note is added to the method signature telling the user where the method comes from. The `--embed-mixin` command-line option can also take wildcard values in order to match specific namespaces. For instance, you can embed only mixins inside of a "Foo::Bar" namespace by doing: !!!sh $ yard doc --embed-mixin "Foo::Bar::*" ## Internationalization (I18n) support for translating docs YARD now ships with the beginnings of internationalization support for translating documentation into multiple languages. The `yard i18n` command now allows you to generate ".pot" and ultimately ".po" files for translation with [gettext](http://www.gnu.org/software/gettext). Note that this tool is a small step in the larger transition for proper I18n support in YARD. We still have to add proper gettext support to our templates for proper generation in multiple languages, but this tool allows you to get started in translating your documents. Improved I18n support will come throughout the 0.8.x series. ## New C parser / handlers architecture (0.8.0) The C parser was completely rewritten to take advantage of YARD's parser and handler architecture. This means more YARD will be more robust when parsing failures occur, tags and directives will now work consistently across Ruby and CRuby files ({tag:!group} will now work, for instance), and developers can now write custom handlers that target CRuby source files. ## YARD will now warn if `@param` name not in method params (0.8.0) YARD will now give you a warning if you use a `@param` tag in your source but give an invalid parameter name. This should catch a lot of common documentation errors and help keep your documentation consistent. ## Added support for `module_function` calls in Ruby code (0.8.0) The `module_function` command in Ruby is now supported in Ruby files. It defines two separate methods, one class and one instance method, both having the exact same docstring, and marks the instance method as private. ## Greatly improved tag documentation using custom template (0.8.0) We have completely revamped the {docs/Tags.md} to include documentation for each meta-data tag and directive with at least one useful example for each one. This was done using template customization and extension available within YARD. ## Tags can now contain '.' for namespacing (0.8.0) Prior to 0.8.0, tags could only contain alphanumeric characters and underscore. YARD now allows the '.' character in tag names, and it is now recommended for namespacing project-specific custom tags. YARD has its own set of custom tags that are namespaced in this way (using the "yard.tagname" namespace). The namespace recommendation is to use "projectname.tagname", or "projectname.component.tagname". ## Added "frames" links for non-framed pages for better nav (0.8.0) Frames navigation has always had a "(no frames)" link to get rid of the frameset. YARD 0.8.0 introduces a "(frames)" link on non-framed pages to reverse this, allowing you to navigate between framed and frameless pages seamlessly. ## Added Gemfile support to YARD server for local gem sets (0.8.0) The `yard server` command now supports `--gemfile` to serve gems from a Gemfile.lock, instead of all system-wide gems. ## Server now displays README on index route like static docs (0.8.0) The `yard server` command will now behave like static docs regarding the index action for a project, listing the README file if present before displaying the alphabetic index. Note that the route for the alphabetic index page has now moved to the explicit '/index' action. ## Added line numbers to `yard stats --list-undoc --compact` (0.8.0) Line numbers are now listed in the compact listing of undocumented objects so that they can be more easily located in the files. ## Single object db now default (multi-object db unsupported) (0.8.0) YARD previously would split the .yardoc db into multiple marshal files for load-time performance reasons if it grew past a specific number of objects. This check is now disabled, and YARD will never automatically switch to a multi-object DB. YARD will now always use the single object db unless explicitly set with `--no-single-db`. If YARD is taking a long time to load your .yardoc database, you can try using this option to split your database into multiple files, but note that this can cause problems with certain codebases (specifically, if you have class methods using the same name as a module/class). ## Added `--api` tag to generate documentation for API sets (0.8.1) You can now use `yardoc --api APINAME` to generate documentation only for objects with the `@api APINAME` tag (or any parent namespace objects, since this tag is transitive). Multiple `--api` switches may be used to generate documentation for multiple APIs together. The following generates documentation for both the "public" and "developer" APIs, also including any objects with undefined API (via `--no-api`): $ yard doc --api public --api developer --no-api Note that if you use `--api`, you must ensure that you also add `@api` tags to your namespace objects (modules and classes), not just your methods. If you do not want to do this, you can also include all objects with *no* `@api` tag by using `--no-api` as shown above. Remember that applying an `@api` tag to a class or module will apply it to all children that do not have this tag already defined, so you can declare an entire class public by applying it to the class itself. Note also that these tags can be overridden by child elements if the tag is re-applied to the individual object. This feature is a simplified version of the more powerful `--query` switch. The query to display the same API documentation as the above example would be: $ yard doc --query '!@api || @api.text =~ /^(public|private)$/' But note that `--query` does not work when YARD is in "safe mode" due to security concerns, whereas `--api` works in either mode. This enables `--api` to function on remote documentation sites like [rubydoc.info](http://rubydoc.info). ## Added `--non-transitive-tag` to disable transitive tag (0.8.3) You can now use `--non-transitive-tag` to disable transitivity on tags that are defined as transitive by default. For instance, in some cases you might not want the @api tag to apply to all methods when you define it on a class. Only the class itself has a specific @api tag. To do this, you can mark @api as non-transitive with: $ yard doc --non-transitive-tag api --api some_api Which will avoid classifying treating @api as a transitive tag when parsing modules and classes. ## Added `-B/--bind` to bind to a port in yard server (0.8.4) You can now bind the `yard server` command to a given local port with `yard server -B PORT` or `yard server --bind PORT`. ## Added `asciidoc` markup type support (0.8.6) Support for the AsciiDoc markup type is now introduced using the `asciidoc` markup type (`yard doc -m asciidoc`). Requires the [asciidoctor](http://rubygems.org/gems/asciidoctor) RubyGem library to be installed before running YARD. ## Added `yard markups` command to list available markup types (0.8.6) You can now list all available markup types and their respective providers by typing `yard markups`. This list also includes the file extensions used to auto-identify markup types for extra files and READMEs. To use a markup in the list, call `yard doc` with `-m MARKUP_TYPE`. To select a specific markup provider library, pass the `-M PROVIDER_NAME` option. ## Added `yard display` command to display formatted objects (0.8.6)

            This feature requires the .yardoc registry to have already been generated. To generate the registry, run yard doc -n.

            You can now display a single object (or a list of objects) in the YARD registry using the `yard display OBJECT ...` command. For example, to display the `YARD::CodeObjects` module as text (the way it is displayed in `yri`), type: $ yard display YARD::CodeObjects You can also format individual objects as HTML. For example, you can format the above object as HTML and pipe the contents into a file readable by a web browser: $ yard display -f html YARD::CodeObjects > codeobjects.html Custom templating options from `yard doc` can also be used, see `yard display --help` for more options. ## Added `--layout` to `yard display` command (0.8.6.1) The `yard display` command now accepts `--layout` to wrap content in a layout template. Currently the `layout` and `onefile` layout templates are supported, though any template can be used. If no parameter is specified, the layout will default to the `layout` template. Example usage: $ yard display --layout onefile -f html YARD::CodeObjects > codeobjects.html The above generates a `codeobjects.html` file that is self-contained with CSS stylesheets and JavaScript code. This is similar to calling `yard doc --one-file` with only the YARD::CodeObjects object in the registry. Note that even though this uses the onefile template, the README file will not be auto-included the way it is with the `yard doc` command. To include the README text at the top of the onefile template, pass the --readme switch: $ yard display --layout onefile -f html --readme README.md OBJECT > out.html # What's New in 0.7.x? 1. **Macro support and detection of DSL methods** (0.7.0) 2. **Inherited attributes now show in HTML output** (0.7.0) 3. **The 'app' directory is now parsed by default** (0.7.0) 4. **Added support for metadata (@title, @markup) in extra files/readmes** (0.7.0) 5. **Added `yard list` command (alias for `yardoc --list`)** (0.7.0) 6. **Added Git support in `yard diff`** (0.7.0) 7. **Added `{include:file:FILENAME}` syntax** (0.7.0) 8. **Added `{render:OBJECT}` syntax to embed object docs in extra files** (0.7.0) 9. **Added improved templates API for custom CSS/JS/menus** (0.7.0) 10. **Added Ruby markup type (`-m ruby`)** (0.7.0) 11. **Added state tracking variables to Parser/Handler architecture** (0.7.0) 12. **Added before/after callbacks to SourceParser** (0.7.0) 13. **Can now use `--yardopts FILE` to specify a custom yardopts file** (0.7.0) 14. **Added new `-t guide` template for guide based docs** (0.7.0) 15. **Github Flavoured Markdown now works out-of-box** (0.7.4) 16. **Added `-m textile_strict` and `-m pre` markup types** (0.7.4) 17. **Reorganized markup types 'text' and 'none'** (0.7.4) 18. **Add support for `rb_define_alias`** (0.7.4) ## Macro support and detection of DSL methods (0.7.0) YARD will now automatically detect class level method calls, similar to the way it knows what an `attr_accessor` is. By simply adding documentation to your class level declarations, YARD can automatically detect them as methods or attributes in your class. Consider DataMapper's "property" declaration: class Post # @attribute # @return [String] the title of the post property :title, String end The above declaration would be created as the `Post#title`. The optional `@attribute` tag tells YARD that the property is an "attribute", and not just a regular method. In addition to basic DSL method detection, YARD also supports macros to create docstrings that can be copies to other objects; these macros can also be "attached" to class level methods to create implicit documentation for macros. Macros and DSL method detection are discussed in much more detail in the {file:docs/GettingStarted.md}, so you should read about them there if you're interested in this feature. ## Inherited attributes now show in HTML output (0.7.0) Inherited attributes will now show up in HTML documentation using the default template in the same manner that inherited methods do. ## The 'app' directory is now parsed by default (0.7.0) YARD tries to follow the "It Just Works" attitude in writing developer tools, and therefore has added `app/**/*.rb` to the default list of globs that it searches for code in. You no longer need to create a `.yardopts` just to list your app directory when documenting your code on rubydoc.info. We should have done this a while ago! And don't worry, YARD still checks lib and ext by default, too. ## Added support for metadata (@title, @markup) in extra files/readmes (0.7.0) Extra files (READMEs, ChangeLogs, LICENSE files, and other guides) now support metadata tags, just like docstrings in code comments. By adding @tag values to the top of a file (no whitespace preceding it) inside of a `# comment` line, YARD will detect and parse these tags and store it for later usage. Tags can contain arbitrary data as well as arbitrary tag names, however the tag names @title and @markup are reserved to specify the document title and markup format respectively. The title will be used in the file list menu, index page, as well as any linking of the file via the `{file:Filename}` syntax. An example of a document with metadata would be: # @title The Best Project Ever! # @markup rdoc # @author Foo Bar (custom tag, does not display in templates) = This Project Rules == Contents ... Note that previous versions of YARD recommended specifying the markup of an extra file with the `#!markup` shebang, but the `@markup` metadata tag is now the "best practice" for specifying the markup format of an extra file. ## Added `yard list` command (alias for `yardoc --list`) (0.7.0) The `yardoc --list` command is used to list objects that are parsed from a codebase. This can be used to grep methods/classes in a codebase from the command line. `yard list` now calls `yardoc --list` as a convenience command. Note that the `yardoc --list` command may eventually be replaced by a more feature-filled `yard list` command, so `yard list` should be used instead of `yardoc --list` when possible. ## Added Git support in `yard diff` (0.7.0) The `yard diff` command can now perform object diffing on git repositories. Provide the `--git` switch to `yard diff` with 2 commit/branches like so: $ yard diff --git HEAD~5 HEAD Added objects: YARD::Parser::SourceParser#contents YARD::Parser::SourceParser#globals ... ## Added `{include:file:FILENAME}` syntax (0.7.0) You can now use the `{include:file:FILENAME}` syntax to embed the contents of an extra file marked up in its markup format. This syntax supports embedding Ruby source files and performing syntax highlighting on the code. ## Added `{render:OBJECT}` syntax to embed object docs in extra files (0.7.0) You can now use the `{render:Object}` syntax to embed the documentation rendering of an entire object (method, class, module) inside of an extra file. This is useful when writing non-API based guides that might require listing a few helper methods or classes. The {file:docs/GettingStarted.md} discussed this syntax in more detail (with example usage). ## Added improved templates API for custom CSS/JS/menus (0.7.0) Plugin & template developers can now more easily insert custom stylesheet or JavaScript files in their customized templates, thanks to an abstraction of the template API. This is documented in the {docs/Templates.md} document. In addition to custom CSS/JS, developers can also create custom menu tabs in both the framed and non framed version of the default theme. ## Added Ruby markup type (`-m ruby`) (0.7.0) The Ruby markup type (`-m ruby`) will now use syntax highlighting for all formatting. This is probably not useful as a global switch, but can be used on individual extra files using the metadata markup specification discussed above. ## Added state tracking variables to Parser/Handler architecture (0.7.0) The parser and handler architecture now contain state variables {YARD::Handlers::Base#extra_state} and {YARD::Handlers::Processor#globals} to share data across handlers and the entire processing phase. `#extra_state` provided a place to store per-file data, while `#globals` gives the developer access to inter-file state when parsing multiple files at once. ## Added before/after callbacks to SourceParser (0.7.0) The {YARD::Parser::SourceParser} class can now register callbacks to execute code before and after parsing of file globs, as well as before and after parsing of individual files. This allows plugin developers to perform setup/teardown (and set global state or update the {YARD::Registry}). See the documentation for the following methods: * {YARD::Parser::SourceParser.before_parse_list} * {YARD::Parser::SourceParser.after_parse_list} * {YARD::Parser::SourceParser.before_parse_file} * {YARD::Parser::SourceParser.after_parse_file} ## Can now use `--yardopts FILE` to specify a custom yardopts file (0.7.0) The `yardoc` command now supports `--yardopts FILE` to specify custom .yardopts options files. This is useful if you have multiple documentation sets, such as a guide documentation set and an API documentation set. ## Added new `-t guide` template for guide based docs (0.7.0) You can now write guide style documentation using a new 'guide' template that only generates documentation for extra files. You would use it in the form: yardoc -t guide - README GettingStarted FAQ TroubleShooting LICENSE This creates the sections for the readme, a getting started, frequently asked questions, trouble shooting and license page. If you need to refer to class / method documentation, you can embed API documentation using the `{render:Object}` tag discussed above. ## Github Flavoured Markdown now works out-of-box (0.7.4) Due to the growing popularity of Github-Flavoured-Markdown (GFM), YARD now uses the Redcarpet library as the default Markdown formatting library with GFM fenced code blocks enabled. This means that you can use fenced code blocks inside of Markdown files with redcarpet installed without any extra code. Previously, users who wanted GFM in their Markdown would have to specify `-m markdown -M redcarpet`, but this is now the default behaviour for YARD. Note that you can still specify language types in code blocks without GFM in YARD by using the "!!!lang" prefix syntax. For example (plain means no markup): !!!plain !!!plain Some code block here. The GFM version would be: !!!plain ```plain Some code block here. ``` ## Added `-m textile_strict` and `-m pre` markup types (0.7.4) A new "textile_strict" markup type was added which behaves exactly like "textile" except it enables hard breaks, so newlines behave as line breaks in the HTML (using `
            ` tags). This option is added for users who want the classic textile behaviour. ## Reorganized markup types 'text' and 'none' (0.7.4) Due to the new pre markup type, the behaviour for text and none were slightly reorganized to be more intuitive. The following behaviours now represent these markup types: * pre: Used to wrap text inside `
            ` tags
             * text: No formatting except for hard breaks (`
            `) on newlines * none: No formatting at all. In all cases, HTML is escaped from input. If you want no HTML escaping, use the html markup type. ## Add support for `rb_define_alias` (0.7.4) CRuby code can now make use of the `rb_define_alias` function. Documentation for aliases is not supported, however. # What's New in 0.6.x? 1. **Local documentation server for RubyGems or projects (`yard server`)** (0.6.0) 2. **Groups support for method listing** (0.6.0) 3. **Single file template (`--one-file`) support** (0.6.0) 4. **`yard` CLI executable with pluggable commands** (0.6.0) 5. **`yard diff` command to object-diff two versions of a project** (0.6.0) 6. **Added `--asset` option to `yardoc`** (0.6.0) 7. **New template API** (0.6.0) 8. **HTML template now adds inline Table of Contents for extra files pages** (0.6.0) 9. **Removed `--incremental` in favour of `--use-cache`** (0.6.0) 10. **Ad-hoc tag registration via `yardoc` CLI (`--tag`, etc.)** (0.6.0) 11. **Added `--transitive-tags` to register transitive tags** (0.6.0) 12. **`yardoc` now displays RDoc-like statistics (`--no-stats` to hide)** (0.6.0) 13. **`yri` now works on constants** (0.6.0) 14. **Plugins are no longer auto-loaded (added `--plugin` switch)** (0.6.2) 15. **Added `YARD::Config` API and `~/.yard/config` configuration file** (0.6.2) 16. **Added `yard config` command to view/edit configuration** (0.6.2) 17. **Added `yard server -t` template path switch** (0.6.2) 18. **Added `YARD::Server.register_static_path` for static server assets** (0.6.2) 19. **YARD::Registry is now thread local** (0.6.5) 20. **Support for ripper gem in Ruby 1.8.7** (0.6.5) ## Local documentation server for RubyGems or projects (`yard server`) (0.6.0) The new `yard server` command spawns a documentation server that can serve either documentation for a local project or installed RubyGems. The server will host (by default) on http://localhost:8808. To serve documentation for the active project (in the current directory): $ yard server The server can also run in "incremental" mode for local projects. In this situation, any modified sources will immediately be updated at each request, ensuring that the server always serve the code exactly as it is on disk. Documenting your code in this fashion essentially gives you an efficient a live preview without running a separate command everytime you make a change. To serve documentation for the active project in incremental mode: $ yard server --reload Note that in incremental mode, objects or method groupings cannot be removed. If you have removed objects or modified groupings, you will need to flush the cache by deleting `.yardoc` and (optionally) restarting the server. The documentation server can also serve documentation for all installed gems on your system, similar to `gem server`, but using YARD's functionality and templates. To serve documentation for installed gems: $ yard server --gems Documentation for the gem need not be previously generated at install-time. If documentation for the gem has not been generated, YARD will do this for you on-the-fly. It is therefore possible to speed up your gem installs by using `gem install GEMNAME --no-rdoc` without repercussion. You can also add this switch to your `~/.gemrc` file so that you don't need to re-type it each time. See [this link](http://stackoverflow.com/questions/1789376/how-do-i-make-no-ri-no-rdoc-the-default-for-gem-install) for exact instructions. ## Groups support for method listing (0.6.0) You can now organize methods in a class/module into logical separated groups. These groups apply lexically and are listed in the order they are defined. For instance, to define a group: # @group Rendering an Object # Documentation here def foo; end # Extra documentation... def bar; end # @group Another Group def aaa; end Note that these `@group` and `@endgroup` declarations are not "tags" and should always be separated with at least 1 line of whitespace from any other documentation or code. In the above example, "Rendering an Object" will be listed with "foo" and "bar" above "Another Group", even though "aaa" comes before the two other methods, alphabetically. To end a group, use `@endgroup`. It is not necessary to end a group to start a new one, only if there is an object following the group that should not belong in any group. # @group Group 1 def foo; end # @endgroup # This method should not be listed in any group def bar; end ## Single file template (`--one-file`) support (0.6.0) `yardoc` now has the `--one-file` option to generate a single-file template for small scripts and libraries. In this case, any comments at the top of the script file will be recognized as a README. ## `yard` CLI executable with pluggable commands (0.6.0) The `yardoc` and `yri` commands are not deprecated and can continue to be used. They are shortcuts for `yard doc` and `yard ri` respectively. However, `yard-graph` has been removed. YARD now has a `yard` executable which combines all pre-existing and new commands into a single pluggable command that is both easier to remember and access. To get a list of commands, type `yard --help`. If you are a plugin developer, you can create your own `yard` command by first subclassing the {YARD::CLI::Command} class and then registering this class with the {YARD::CLI::CommandParser.commands} list. For instance: YARD::CLI::CommandParser.commands[:my_command] = MyCommandClass The above line will enable the user to execute `yard my_command [options]`. ## `yard diff` command to object-diff two versions of a project (0.6.0) One of the built-in commands that comes with the new `yard` executable is the ability to do object-oriented diffing across multiple versions of the same project, either by 2 versions of a gem, or 2 working copies. Just like regular diffing tells you which lines have been added/removed in a file, object diffing allows you to see what classes/methods/modules have been added/removed between versions of a codebase. For an overview of how to use `yard diff`, see [YARD Object Oriented Diffing](http://gnuu.org/2010/06/26/yard-object-oriented-diffing/). ## `yard stats` to display statistics and undocumented objects (0.6.0) YARD now outputs the following statistics when `yard stats` is run: Files: 125 Modules: 35 ( 4 undocumented) Classes: 139 ( 29 undocumented) Constants: 53 ( 20 undocumented) Methods: 602 ( 70 undocumented) 85.16% documented Note that these statistics are based on what you have set to show in your documentation. If you use `@private` tags and/or do not display private/protected methods in your documentation, these will not show up as undocumented. Therefore this metric is contextual. You can also specifically list all undocumented objects (and their file locations) with the `--list-undoc` option. ## Added `--asset` option to `yardoc` (0.6.0) The `yardoc` command can now take the `--asset` option to copy over files/directories (recursively) to the output path after generating documentation. The format of the argument is "from:to" where from is the source path and to is the destination. For instance, YARD uses the following syntax in the `.yardopts` file to copy over image assets from the 'docs/images' directory into the 'images' directory after generating HTML: --asset docs/images:images ## New template API (0.6.0) The new template API allows for easier insertion of sections within an inherited template. You should no longer need to insert by index, an error-prone process that could break when a template is updated. Instead of: sections.last.place(:my_section).before(:another_section) use: sections.place(:my_section).before_any(:another_section) You can see more in the {file:docs/Templates.md#Inserting_and_Traversing_Sections} document. ## HTML template now adds inline Table of Contents for extra files pages (0.6.0) A table of contents is now generated dynamically using JavaScript for extra file pages (such as README's, or this document). It is generated based off the headers (h1,h2,... tags) used in the document, and can be floated to the right or listed inline on the page. ## Ad-hoc tag registration via `yardoc` CLI (`--tag`, etc.) (0.6.0) Simple meta-data tags can now be added at the command-line and registered to display in templates in a number of pre-defined ways. For instance, to create a freeform text tag, use the following: --tag my_tag_name:"My Tag Title" You can also create a "typed" tag (similar to `@return`), a typed named tag (similar to `@param`) as well as various combinations. The full list of options are listed in `yardoc --help` under the "Tag Options" section. If you wish to create a tag to store data but do not wish to show this data in the templates, use the `--hide-tag` option to hide it from generated output: --hide-tag my_tag_name ## Added `--transitive-tags` to register transitive tags (0.6.0) Transitive tags are tags that apply to all descendants of a namespace (class or module) when documented on that namespace. For instance, the `@since` tag is a transitive tag. Applying `@since` to a class will automatically apply `@since` to all methods in the class. Creating a `@since` tag directly on a method will override the inherited value. You can specify transitive tags on the command-line by using this option. Note that the tags must already exist (built-in or created with the `--tag` option) to be specified as transitive. If you wish to do this programmatically, see the {YARD::Tags::Library.transitive_tags} attribute. ## `yardoc` now displays RDoc-like statistics (`--no-stats` to hide) (0.6.0) As seen in the `yard stats` feature overview, `yardoc` displays RDoc-like statistics when it is run. The output is equivalent to typing `yard stats`. To hide this output when yardoc is run, use `--no-stats`. ## `yri` now works on constants (0.6.0) Templates have now been added for text view of constants, which displays any documentation and the constant value. ## Plugins are no longer auto-loaded (added `--plugin` switch) (0.6.2) This is a backwards-incompatible change that disables plugins from automatically loading when YARD starts up. From now on, you should manually declare which plugins your project is using by adding `--plugin PLUGINNAME` to a `.yardopts` file in the root of your project. You can also re-enable autoloaded plugins by setting `load_plugins` to true in your configuration file (`yard config load_plugins true`, see next item). You can also set `autoload_plugins` to a list of plugins to be automatically loaded on start. If you are a YARD plugin author, please make sure to inform your users of these changes. Note that `--plugin` switches passed on the commandline (not via `.yardopts`) are parsed before commands are loaded, and therefore can add in new CLI commands. ## Added `YARD::Config` API and `~/.yard/config` configuration file (0.6.2) There is a new global configuration API that can be accessed programmatically and set via the `~/.yard/config` file. The file is encoded as a YAML file, and looks like: :load_plugins: false :ignored_plugins: - my_plugin - my_other_plugin :autoload_plugins: - my_autoload_plugin :safe_mode: false You can also set configuration options via the command-line (see next item). ## Added `yard config` command to view/edit configuration (0.6.2) A new `yard config` command was created to view or edit the configuration file via the commandline. * To view the current configuration use `yard config --list`. * To view a specific item use `yard config ITEMNAME` * To modify an item value use `yard config ITEMNAME VALUE` ## Added `yard server -t` template path switch (0.6.2) The `yard server` command now accepts `-t` or `--template-path` to register a new template path for template customization. ## Added `YARD::Server.register_static_path` for static server assets (0.6.2) The server now supports a command to register static asset paths. If you are extending the YARD::Server modules, make sure to register your asset paths through this method. ## YARD::Registry is now thread local (0.6.5) Creating a new thread will now implicitly load a new Registry that can be used to parse and process new code objects independently of the other threads. Note that this means you can no longer use the Registry across threads; you must either access the threadlocal object directly, or synchronize threads to do the processing in the initial registry's thread. ## Support for ripper gem in Ruby 1.8.7 (0.6.5) YARD now supports the Ruby 1.8.7 port of the `ripper` gem to improve parsing of source, both in terms of performance and functionality. When the `ripper` gem is available, YARD will use the "new-style" handlers. You can take advantage of this functionality by performing a `gem install ripper`. What's New in 0.5.x? ==================== 1. **Support for documenting native Ruby C code** (0.5.0) 2. **Incremental parsing and output generation with `yardoc -c`** (0.5.0, 0.5.3) 2. **Improved `yri` support to perform lookups on installed Gems** (0.5.0) 3. **Added `yardoc --default-return` and `yardoc --hide-void-return`** (0.5.0) 4. **Multiple syntax highlighting language support** (0.5.0) 5. **New .yardoc format** (0.5.0) 6. **Support for yard-doc-* gem packages as hosted .yardoc dbs** (0.5.1) 7. **Support for extra search paths in `yri`** (0.5.1) 8. **Generating HTML docs now adds frames view** (0.5.3) 9. **Tree view for class list** (0.5.3) 10. **Ability to specify markup format of extra files** (0.5.3) 11. **Keyboard shortcuts for default HTML template** (0.5.4) Support for documenting native Ruby C code (0.5.0) -------------------------------------------------- It is now possible to document native Ruby extensions with YARD with a new C parser mostly borrowed from RDoc. This enables the ability to document Ruby's core and stdlibs which will be hosted on http://yardoc.org/docs. In addition, the .yardoc dump for the Ruby-core classes will become available as an installable gem for yri support (see #3). Incremental parsing and output generation with `yardoc -c` (0.5.0, 0.5.3) -------------------------------------------------------------------------

            Note: in 0.5.3 and above you must use --incremental to incrementally generate HTML, otherwise only parsing will be done incrementally but HTML will be generated with all objects. --incremental implies -c, so no need to specify them both.

            YARD now compares file checksums before parsing when using `yardoc -c` (aka `yardoc --use-cache`) to do incremental parsing of only the files that have changed. HTML (or other output format) generation will also only be done on the objects that were parsed from changed files (\*). This makes doing a documentation development cycle much faster for quick HTML previews. Just remember that when using incremental output generation, the index will not be rebuilt and inter-file links might not hook up right, so it is best to perform a full rebuild at the end of such previews. (\*) Only for versions prior to 0.5.3. For 0.5.3+, use `--incremental` for incremental HTML output. Improved `yri` support to perform lookups on installed Gems (0.5.0) ------------------------------------------------------------------- The `yri` executable can now perform lookups on gems that have been parsed by yard. Therefore, to use this command you must first parse all gems with YARD. To parse all gems, use the following command: $ sudo yardoc --build-gems The above command builds a .yardoc file for all installed gems in the respective gem directory. If you do not have write access to the gem path, YARD will write the yardoc file to `~/.yard/gem_index/NAME-VERSION.yardoc`. Note: you can also use `--re-build-gems` to force re-parsing of all gems. You can now do lookups with yri: $ yri JSON All lookups are cached to `~/.yard/yri_cache` for quicker lookups the second time onward. Added `yardoc --default-return` and `yardoc --hide-void-return` (0.5.0) ----------------------------------------------------------------------- YARD defaults to displaying (Object) as the default return type of any method that has not declared a @return tag. To customize the default return type, you can specify: $ yardoc --default-return 'MyDefaultType' You can also use the empty string to list no return type. In addition, you can use --hide-void-return to ignore any method that defines itself as a void type by: `@return [void]` Multiple syntax highlighting language support (0.5.0) ----------------------------------------------------- YARD now supports the ability to specify a language type for code blocks in docstrings. Although no actual highlighting support is added for any language but Ruby, you can add your own support by writing your own helper method: # Where LANGNAME is the language: def html_syntax_highlight_LANGNAME(source) # return highlighted HTML end To use this language in code blocks, prefix the block with `!!!LANGNAME`: !!!plain !!!python def python_code(self): return self By the same token. you can now use `!!!plain` to ignore highlighting for a specific code block. New .yardoc format (0.5.0) -------------------------- To make the above yri support possible, the .yardoc format was redesigned to be a directory instead of a file. YARD can still load old .yardoc files, but they will be automatically upgraded if re-saved. The new .yardoc format does have a larger memory footprint, but this will hopefully be optimized downward. Support for yard-doc-* gem packages as hosted .yardoc dbs (0.5.1) ----------------------------------------------------------------- You can now install special YARD plugin gems titled yard-doc-NAME to get packaged a .yardoc database. This will enable yri lookups or building docs for the gem without the code. One main use for this is the `yard-doc-core` package, which enabled yri support for Ruby core classes (stdlib coming soon as `yard-doc-stdlib`). To install it, simply: $ sudo gem install yard-doc-core # now you can use: $ yri String This will by default install the 1.9.1 core library. To install a library for a specific version of Ruby, use the `--version` switch on gem: $ sudo gem install --version '= 1.8.6' yard-doc-core Support for extra search paths in `yri` (0.5.1) ----------------------------------------------- You can now add custom paths to non-gem .yardoc files by adding them as newline separated paths in `~/.yard/yri_search_paths`. Generating HTML docs now adds frames view (0.5.3) ------------------------------------------------- `yardoc` will now create a `frames.html` file when generating HTML documents which allows the user to view documentation inside frames, for those users who still find frames beneficial. Tree view for class list (0.5.3) -------------------------------- The class list now displays as an expandable tree view to better organized an otherwise cluttered namespace. If you properly namespace your less important classes (like Rails timezone classes), they will not take up space in the class list unless the user looks for them. Ability to specify markup format of extra files (0.5.3) ------------------------------------------------------- You can now specify the markup format of an extra file (like README) at the top of the file with a shebang-like line: #!textile contents here The above file contents will be rendered with a textile markup engine (eg. RedCloth). Keyboard shortcuts for default HTML template (0.5.4) ---------------------------------------------------- You can now access the "Class List", "Method List" and "File List" with the 'c', 'm' and 'f' keyboard shortcuts in the default HTML template, allowing for keyboard-only navigation around YARD documentation. API for registering custom parsers (0.5.6) ------------------------------------------ You can now register parsers for custom source languages by calling the following method: SourceParser.register_parser_type(:java, MyJavaParser, 'java') The parser class MyJavaParser should be a subclass of {YARD::Parser::Base}, and the last argument is a set of extensions (string, array or regexp). You can read more about registering parsers at the {YARD::Parser::SourceParser} class documentation. What's New in 0.4.x? ==================== 1. **New templating engine and templates** 2. **yardoc `--query` argument** 3. **Greatly expanded API documentation** 4. **New plugin support** 5. **New tags (@abstract, @private)** 6. **Default rake task is now `rake yard`** New templating engine and templates ----------------------------------- The templates were redesigned, most notably removing the ugly frameset, adding search to the class/method lists, simplifying the layout and making things generally prettier. You should also notice that more tags are now visible in the templates such as @todo, the new @abstract and @note tags and some others that existed but were previously omitted from the generated documentation. There is also a new templating engine (based on the tadpole templating library) to allow for much more user customization. You can read about it in {file:docs/Templates.md}. yardoc `--query` argument ------------------------- The yardoc command-line tool now supports queries to select which classes, modules or methods to include in documentation based on their data or meta-data. For instance, you can now generate documentation for your "public" API only by adding "@api public" to each of your public API methods/classes and using the following argument: --query '@api.text == "public"' More information on queries is in the {file:README.md}. Greatly expanded API documentation ---------------------------------- Last release focused on many how-to and architecture documents to explain the design of YARD, but many of the actual API classes/methods were still left undocumented. This release marks a focus on getting YARD's own documentation up to par so that it can serve as an official reference on the recommended conventions to use when documenting code. New plugin support ------------------ YARD now supports loading of plugins via RubyGems. Any gem named `yard-*` or `yard_*` will now be loaded when YARD starts up. Note that the '-' separator is the recommended naming scheme. To ignore plugins, add the gem names to `~/.yard/ignored_plugins` on separate lines (or separated by whitespace). New tags (@abstract, @private) ------------------------------ Two new tags were added to the list of builtin meta-tags in YARD. `@abstract` marks a class/module/method as abstract while `@private` marks an object as "private". The latter tag is used in situations where an object is public due to Ruby's own visibility limitations (constants, classes and modules can never be private) but not actually part of your public API. You should use this tag sparingly, as it is not meant to be an equivalent to RDoc's `:nodoc:` tag. Remember, YARD recommends documenting private objects too. This tag exists so that you can create a query (`--query !@private`) to ignore all of these private objects in your documentation. You can also use the new `--no-private` switch, which is a shortcut to the aforementioned query. You can read more about the new tags in the {file:docs/GettingStarted.md} guide. Default rake task is now `rake yard` ------------------------------------ Not a big change, but anyone using the default "rake yardoc" task should update their scripts: [http://github.com/lsegal/yard/commit/ad38a68dd73898b06bd5d0a1912b7d815878fae0](http://github.com/lsegal/yard/commit/ad38a68dd73898b06bd5d0a1912b7d815878fae0) What's New in 0.2.3.x? ====================== 1. **Full Ruby 1.9 support** 2. **New parser code and handler API for 1.9** 3. **A new `@overload` tag** 4. **Better documentation** 5. **Template changes and bug fixes** Full Ruby 1.9 support --------------------- YARD's development actually focuses primarily on 1.9 from the get-go, so it is not an afterthought. All features are first implemented for compatibility with 1.9, but of course all functionality is also tested in 1.8.x. YARD 0.2.2 was mostly compatible with 1.9, but the new release improves and extends in certain areas where compatibility was lacking. The new release should be fully functional in Ruby 1.9. New parser code and handler API for 1.9 --------------------------------------- Using Ruby 1.9 also gives YARD the advantage of using the new `ripper` library which was added to stdlib. The ripper parser is Ruby's official answer to projects like ParseTree and ruby2ruby. Ripper allows access to the AST as it is parsed by the Ruby compiler. This has some large benefits over alternative projects: 1. It is officially supported and maintained by the Ruby core team. 2. The AST is generated directly from the exact same code that drives the compiler, meaning anything that compiles is guaranteed to generate the equivalent AST. 3. It needs no hacks, gems or extra libs and works out of the box in 1.9. 4. It's *fast*. Having the AST means that developers looking to extend YARD have much better access to the parsed code than in previous versions. The only caveat is that this library is not back-compatible to 1.8.x. Because of this, there are subtle changes to the handler extension API that developers use to extend YARD. Namely, there is now a standard API for 1.9 and a "legacy" API that can run in both 1.8.x and 1.9 if needed. A developer can still use the legacy API to write handlers that are compatible for both 1.8.x and 1.9 in one shot, or decide to implement the handler using both APIs. Realize that the benefit of using the new API means 1.9 users will get a 2.5x parsing speed increase over running the legacy handlers (this is *in addition to* the ~1.8x speed increase of using YARV over MRI). A new `@overload` tag --------------------- The new `@overload` tag enables users to document methods that take multiple parameters depending on context. This is basically equivalent to RDoc's call-seq, but with a name that is more akin to the OOP concept of method overloading that is actually being employed. Here's an example: # @overload def to_html(html, autolink = true) # This docstring describes the specific overload only. # @param [String] html the HTML # @param [Boolean] autolink whether or not to atuomatically link # URL references # @overload def to_html(html, opts = {}) # @param [String] html the HTML # @param [Hash] opts any attributes to add to the root HTML node def to_html(*args) # split args depending on context end As you can see each overload takes its own nested tags (including a docstring) as if it were its own method. This allows "virtual" overloading behaviour at the API level to make Ruby look like overload-aware languages without caring about the implementation details required to add the behaviour. It is still recommended practice, however, to stay away from overloading when possible and document the types of each method's real parameters. This allows toolkits making use of YARD to get accurate type information for your methods, for instance, allowing IDE autocompletion. There are, of course, situations where overload just makes more sense. Better documentation -------------------- The first few iterations of YARD were very much a proof of concept. Few people were paying attention and it was really just pieced together to see what was feasible. Now that YARD is gaining interest, there are many developers that want to take advantage of its extensibility support to do some really cool stuff. Considerable time was spent for this release documenting, at a high level, what YARD can do and how it can be done. Expect this documentation to be extended and improved in future releases. Template changes and bug fixes ------------------------------ Of course no new release would be complete without fixing the old broken code. Some tags existed but were not present in generated documentation. The templates were mostly fixed to add the major omitted tags. In addition to template adjustments, many parsing bugs were ironed out to make YARD much more stable with existing projects (Rails, HAML, Sinatra, Ramaze, etc.). yard-0.8.7.3/.yardopts0000644000004100000410000000103312261240652014521 0ustar www-datawww-data--protected --no-private --embed-mixin ClassMethods --exclude /server/templates/ --exclude /yard/rubygems/ --asset docs/images:images --tag yard.signature:"YARD Tag Signature" --type-name-tag yard.tag:"YARD Tag" --type-name-tag yard.directive:"YARD Directive" --hide-tag yard.tag --hide-tag yard.directive --hide-tag yard.signature --load ./docs/templates/plugin.rb - docs/WhatsNew.md docs/GettingStarted.md docs/Tags.md docs/Overview.md docs/CodeObjects.md docs/Parser.md docs/Handlers.md docs/TagsArch.md docs/Templates.md LICENSE LEGAL yard-0.8.7.3/LICENSE0000644000004100000410000000204312261240652013662 0ustar www-datawww-dataCopyright (c) 2007-2013 Loren Segal Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.yard-0.8.7.3/benchmarks/0000755000004100000410000000000012261240652014773 5ustar www-datawww-datayard-0.8.7.3/benchmarks/splat_vs_flatten.rb0000644000004100000410000000054612261240652020675 0ustar www-datawww-datarequire "benchmark" # To prove that flattening a small list is not significantly slower than # calling *list (used to get around create_tag list issue) $a = "FOO BAR BAZ" def foo(*args) args.last.inspect end TESTS = 10_000 Benchmark.bmbm do |x| x.report("splat") { TESTS.times { foo *$a } } x.report("flatten") { TESTS.times { foo *[$a].flatten } } endyard-0.8.7.3/benchmarks/generation.rb0000644000004100000410000000216012261240652017452 0ustar www-datawww-datarequire "benchmark" require File.join(File.dirname(__FILE__), '..', 'lib', 'yard') unless YARD::CodeObjects::Proxy.private_instance_methods.include?('to_obj') raise "This benchmark is dependent on YARD::CodeObjects::Proxy#to_obj" end def rungen YARD::Registry.clear YARD::CLI::Yardoc.run('--quiet', '--use-cache') end def redef(lock = false) eval <<-eof class YARD::CodeObjects::Proxy; def to_obj @obj #{lock ? '||' : ''}= YARD::Registry.resolve(@namespace, @name) end end eof end Benchmark.bmbm do |x| x.report("gen-w/o-locking") { redef; rungen } x.report("gen-with-locking") { redef(true); rungen } end =begin Results from 2008-06-07 Rehearsal ---------------------------------------------------- gen-w/o-locking 9.650000 0.450000 10.100000 ( 10.150556) gen-with-locking 7.790000 0.400000 8.190000 ( 8.373811) ------------------------------------------ total: 18.290000sec user system total real gen-w/o-locking 9.820000 0.430000 10.250000 ( 10.293283) gen-with-locking 7.820000 0.380000 8.200000 ( 8.243326) =endyard-0.8.7.3/benchmarks/builtins_vs_eval.rb0000644000004100000410000000166412261240652020677 0ustar www-datawww-datarequire 'benchmark' require File.join(File.dirname(__FILE__), '..', 'lib', 'yard') TIMES = (ARGV[0] || 10_000).to_i def bench_builtins(name) YARD::CodeObjects::BUILTIN_EXCEPTIONS_HASH.has_key? name end def bench_eval(name) eval(name).is_a?(Class) rescue false end Benchmark.bmbm do |b| b.report("builtins PASS") { TIMES.times {YARD::CodeObjects::BUILTIN_EXCEPTIONS.each {|y| bench_builtins(y) } } } b.report("eval PASS") { TIMES.times {YARD::CodeObjects::BUILTIN_EXCEPTIONS.each {|y| bench_eval(y) }} } b.report("builtins FAIL") { TIMES.times {YARD::CodeObjects::BUILTIN_MODULES.each {|y| bench_builtins(y) } } } b.report("eval FAIL") { TIMES.times {YARD::CodeObjects::BUILTIN_MODULES.each {|y| bench_eval(y) }} } b.report("builtins ANY") { TIMES.times {YARD::CodeObjects::BUILTIN_CLASSES.each {|y| bench_builtins(y) } } } b.report("eval ANY") { TIMES.times {YARD::CodeObjects::BUILTIN_CLASSES.each {|y| bench_eval(y) }} } endyard-0.8.7.3/benchmarks/template_erb.rb0000644000004100000410000000122112261240652017757 0ustar www-datawww-datarequire "benchmark" require File.join(File.dirname(__FILE__), '..', 'lib', 'yard') YARD::Registry.load_yardoc(File.join(File.dirname(__FILE__), '..', '.yardoc')) obj = YARD::Registry.at("YARD::CodeObjects::Base") TIMES = 3 Benchmark.bm do |x| x.report("trim-line") { TIMES.times { obj.format(:format => :html) } } module YARD module Templates module Template def erb(section, &block) erb = ERB.new(cache(section), nil) erb.filename = cache_filename(section).to_s erb.result(binding, &block) end end end end x.report("no-trim ") { TIMES.times { obj.format(:format => :html) } } endyard-0.8.7.3/benchmarks/yri_cache.rb0000644000004100000410000000062312261240652017247 0ustar www-datawww-datarequire File.dirname(__FILE__) + "/../lib/yard" require "benchmark" include YARD::CLI class YARD::CLI::YRI def print_object(object) end end def remove_cache File.unlink(YRI::CACHE_FILE) end TIMES = 10 NAME = 'YARD' remove_cache; YRI.run(NAME) Benchmark.bmbm do |x| x.report("cache ") { TIMES.times { YRI.run(NAME) } } x.report("no-cache") { TIMES.times { remove_cache; YRI.run(NAME) } } endyard-0.8.7.3/benchmarks/marshal_vs_dbm.rb0000644000004100000410000000352012261240652020301 0ustar www-datawww-datarequire 'benchmark' require 'dbm' MARSHAL_FILE = "marshal_test.db" DBM_FILE = "dbm_test" WRITE_TIMES = 1 READ_TIMES = 100 NUM_INDICES = 10000 INDICES = ['33', '857', '5022', '8555'] def generate_index '0' * (rand * 4096).floor end def write_dbm File.unlink(DBM_FILE + ".db") if File.exist?(DBM_FILE + ".db") handle = DBM.new(DBM_FILE) NUM_INDICES.times {|t| handle[t.to_s] = Marshal.dump(generate_index) } handle.close end def read_dbm db = DBM.open(DBM_FILE) INDICES.each {|index| Marshal.load(db[index]) } db.close end def write_marshal File.unlink(MARSHAL_FILE) if File.exist?(MARSHAL_FILE) handle = {} NUM_INDICES.times {|t| handle[t.to_s] = generate_index } File.open(MARSHAL_FILE, "wb") {|f| f.write(Marshal.dump(handle)) } end def read_marshal db = Marshal.load(File.read(MARSHAL_FILE)) INDICES.each {|index| db[index] } end Benchmark.bmbm do |x| x.report("marshal-write") { WRITE_TIMES.times { write_marshal } } x.report("dbm-write") { WRITE_TIMES.times { write_dbm } } x.report("marshal-read ") { READ_TIMES.times { read_marshal } } x.report("dbm-read ") { READ_TIMES.times { read_dbm } } end File.unlink(MARSHAL_FILE) File.unlink(DBM_FILE + ".db") __END__ Rehearsal ------------------------------------------------- marshal-write 0.090000 0.070000 0.160000 ( 0.465820) dbm-write 0.560000 0.570000 1.130000 ( 3.045556) marshal-read 4.640000 3.180000 7.820000 ( 7.821978) dbm-read 0.020000 0.020000 0.040000 ( 0.070920) ---------------------------------------- total: 9.150000sec user system total real marshal-write 0.080000 0.050000 0.130000 ( 0.436561) dbm-write 0.560000 0.550000 1.110000 ( 2.030530) marshal-read 4.670000 3.180000 7.850000 ( 7.842232) dbm-read 0.010000 0.020000 0.030000 ( 0.053928) yard-0.8.7.3/benchmarks/pathname_vs_string.rb0000644000004100000410000000353712261240652021223 0ustar www-datawww-datarequire 'pathname' require "benchmark" require File.dirname(__FILE__) + '/../lib/yard' pathobj = Pathname.new("a/b/c") strobj = "a/b/c" TIMES = 1_000 log.puts "join:" Benchmark.bmbm do |x| x.report("pathname") { TIMES.times { Pathname.new("a/b/c").join("d", "e", "f") } } x.report("string ") { TIMES.times { File.join("a/b/c", "d", "e", "f") } } x.report("pathname-sameobject") { TIMES.times { pathobj.join("d", "e", "f") } } x.report("string-sameobject ") { TIMES.times { File.join(strobj, "d", "e", "f") } } end log.puts log.puts log.puts "cleanpath:" Benchmark.bmbm do |x| x.report("pathname") { TIMES.times { Pathname.new("a/b//.././c").cleanpath } } x.report("string ") { TIMES.times { File.cleanpath("a/b//.././c") } } end __END__ join: Rehearsal ------------------------------------------------------- pathname 0.330000 0.020000 0.350000 ( 0.353481) string 0.010000 0.000000 0.010000 ( 0.001390) pathname-sameobject 0.360000 0.020000 0.380000 ( 0.384473) string-sameobject 0.000000 0.000000 0.000000 ( 0.001187) ---------------------------------------------- total: 0.740000sec user system total real pathname 0.330000 0.020000 0.350000 ( 0.350820) string 0.000000 0.000000 0.000000 ( 0.001055) pathname-sameobject 0.330000 0.010000 0.340000 ( 0.346949) string-sameobject 0.000000 0.000000 0.000000 ( 0.001141) cleanpath: Rehearsal -------------------------------------------- pathname 0.060000 0.000000 0.060000 ( 0.059767) string 0.010000 0.000000 0.010000 ( 0.013775) ----------------------------------- total: 0.070000sec user system total real pathname 0.060000 0.000000 0.060000 ( 0.059697) string 0.020000 0.000000 0.020000 ( 0.013624)yard-0.8.7.3/benchmarks/template_format.rb0000644000004100000410000000042212261240652020501 0ustar www-datawww-datarequire "benchmark" require File.join(File.dirname(__FILE__), '..', 'lib', 'yard') YARD::Registry.load_yardoc(File.join(File.dirname(__FILE__), '..', '.yardoc')) obj = YARD::Registry.at("YARD::CodeObjects::Base") log.puts Benchmark.measure { obj.format(:format => :html) } yard-0.8.7.3/benchmarks/erb_vs_erubis.rb0000644000004100000410000000216112261240652020151 0ustar www-datawww-datarequire 'rubygems' require 'erubis' require 'erubis/tiny' require 'erb' require "benchmark" require File.join(File.dirname(__FILE__), '..', 'lib', 'yard') def rungen YARD::Registry.load_yardoc(File.join(File.dirname(__FILE__), '..', '.yardoc')) YARD::Registry.at("YARD::CodeObjects::Base").format(:format => :html) end Benchmark.bmbm do |x| x.report("erubis") do eval <<-eof module YARD; module Templates; module Template def erb_with(str, x) Erubis::Eruby.new(str) end end end end eof rungen end x.report("fast-erubis") do eval <<-eof module YARD; module Templates; module Template def erb_with(str, x) Erubis::FastEruby.new(str) end end end end eof rungen end x.report("tiny-erubis") do eval <<-eof module YARD; module Templates; module Template def erb_with(str, x) Erubis::TinyEruby.new(str) end end end end eof rungen end x.report("erb") do eval <<-eof module YARD; module Templates; module Template def erb_with(str, x) ERB.new(str, nil) end end end end eof rungen end endyard-0.8.7.3/benchmarks/concat_vs_join.rb0000644000004100000410000000052212261240652020315 0ustar www-datawww-datarequire "benchmark" STR1 = "Hello" JOIN = "::" STR2 = "World" TESTS = 100_000 Benchmark.bmbm do |results| results.report("concat") { TESTS.times { "".concat(STR1).concat(JOIN).concat(STR2) } } results.report("add ") { TESTS.times { STR1 + JOIN + STR2 } } results.report("join ") { TESTS.times { [STR1, STR2].join(JOIN) } } end yard-0.8.7.3/benchmarks/ri_vs_yri.rb0000644000004100000410000000105412261240652017325 0ustar www-datawww-datarequire "benchmark" TIMES = 10 Benchmark.bmbm do |x| x.report("ri") { TIMES.times { `ri -T YARD::Tags::Library` } } x.report("yri") { TIMES.times { `./bin/yri -T YARD::Tags::Library` } } end __END__ Rehearsal --------------------------------------- ri 0.000000 0.020000 6.880000 ( 6.929591) yri 0.000000 0.000000 1.060000 ( 1.074840) ------------------------------ total: 7.940000sec user system total real ri 0.000000 0.020000 6.850000 ( 6.871660) yri 0.000000 0.010000 1.060000 ( 1.067585) yard-0.8.7.3/benchmarks/registry_store_types.rb0000644000004100000410000000275612261240652021642 0ustar www-datawww-datarequire 'benchmark' require File.join(File.dirname(__FILE__), '..', 'lib', 'yard') def parse_and_select_objects YARD::Registry.load_yardoc(File.join(File.dirname(__FILE__), '..', '.yardoc')) YARD::Registry.load_all $paths = [] 4.times { $paths << YARD::Registry.paths[rand(YARD::Registry.paths.size)] } $regular_registry = {} $types_registry = {} YARD::Registry.all.each do |object| $regular_registry[object.path] = object ($types_registry[object.type] ||= {})[object.path] = object end end def run_lookup $paths.select {|path| $regular_registry[path] } end def run_lookup_with_types $paths.select {|path| $types_registry.values.find {|list| list[path] } } end TIMES = 100_000 parse_and_select_objects p $paths Benchmark.bmbm do |x| x.report("normal") { TIMES.times { run_lookup } } x.report("types") { TIMES.times { run_lookup_with_types } } end __END__ # Run on March 22 2012 ["YARD::Parser::Ruby::Legacy::RubyToken::TkUnknownChar#initialize", "YARD::Parser::C::CParser#enumerator", "YARD::CodeObjects::ClassObject#inherited_meths", "YARD::Parser::C::Statement#source="] Rehearsal ---------------------------------------------- normal 0.180000 0.000000 0.180000 ( 0.182640) types 1.150000 0.010000 1.160000 ( 1.160219) ------------------------------------- total: 1.340000sec user system total real normal 0.170000 0.000000 0.170000 ( 0.165621) types 1.140000 0.000000 1.140000 ( 1.142269) yard-0.8.7.3/benchmarks/ripper_parser.rb0000644000004100000410000000100712261240652020173 0ustar www-datawww-data# encoding: utf-8 require 'benchmark' require File.dirname(__FILE__) + '/../lib/yard' $files = Dir[File.dirname(__FILE__) + '/../lib/**/*.rb'].map {|f| File.read(f) } $files_rip = Dir[File.dirname(__FILE__) + '/../lib/**/*.rb'].map {|f| [File.read(f), f] } TIMES = 2 Benchmark.bmbm do |x| x.report("rip-parser") { TIMES.times { $files_rip.each {|f| YARD::Parser::Ruby::RubyParser.parse(*f) } } } x.report("yard-parser ") { TIMES.times { $files.each {|f| YARD::Parser::Ruby::Legacy::StatementList.new(f) } } } endyard-0.8.7.3/benchmarks/rdoc_vs_yardoc.rb0000644000004100000410000000114112261240652020315 0ustar www-datawww-datarequire "benchmark" files = Dir.glob(File.dirname(__FILE__) + '/../lib/**/*.rb').join(" ") Benchmark.bmbm do |x| x.report("rdoc") { `rm -rf rdoc && rdoc -q -o rdoc #{files} && rm -rf rdoc` } x.report("yardoc") { `rm -rf yard && ./bin/yardoc -q -o yard #{files} && rm -rf yard` } x.report("yardoc-cached") { `rm -rf yard && ./bin/yardoc -c -q -o yard #{files} && rm -rf yard` } x.report("yardoc-legacy") { `rm -rf yard && ./bin/yardoc --legacy -q -o yard #{files} && rm -rf yard` } x.report("yardoc-legacy-cached") { `rm -rf yard && ./bin/yardoc --legacy -c -q -o yard #{files} && rm -rf yard` } endyard-0.8.7.3/benchmarks/template_profile.rb0000644000004100000410000000073012261240652020653 0ustar www-datawww-datarequire 'rubygems' require 'ruby-prof' #require 'benchmark' require File.join(File.dirname(__FILE__), '..', 'lib', 'yard') YARD::Registry.load_yardoc(File.join(File.dirname(__FILE__), '..', '.yardoc')) obj = YARD::Registry.at("YARD::CodeObjects::Base") #PerfTools::CpuProfiler.start("template_profile") do #end result = RubyProf.profile do obj.format(:format => :html, :no_highlight => true) end printer = RubyProf::CallTreePrinter.new(result) printer.print(STDOUT) yard-0.8.7.3/benchmarks/parsing.rb0000644000004100000410000000301112261240652016756 0ustar www-datawww-datarequire "benchmark" require 'yard' require 'logger' PATH_ORDER = [ 'lib/yard/autoload.rb', 'lib/yard/code_objects/base.rb', 'lib/yard/code_objects/namespace_object.rb', 'lib/yard/handlers/base.rb', 'lib/yard/generators/helpers/*.rb', 'lib/yard/generators/base.rb', 'lib/yard/generators/method_listing_generator.rb', 'lib/yard/serializers/base.rb', 'lib/**/*.rb' ] Benchmark.bmbm do |x| x.report("parse in order") { YARD::Registry.clear; YARD.parse PATH_ORDER, [], Logger::ERROR } x.report("parse") { YARD::Registry.clear; YARD.parse 'lib/**/*.rb', [], Logger::ERROR } end =begin load_order branch (2008-06-07): Rehearsal -------------------------------------------------- parse in order 6.510000 0.050000 6.560000 ( 6.563223) parse 6.300000 0.040000 6.340000 ( 6.362272) ---------------------------------------- total: 12.900000sec user system total real parse in order 6.310000 0.060000 6.370000 ( 6.390945) parse 6.300000 0.050000 6.350000 ( 6.366709) api_changes branch before merge (2008-06-07) Rehearsal -------------------------------------------------- parse in order 6.330000 0.050000 6.380000 ( 6.397552) parse 6.380000 0.050000 6.430000 ( 6.446954) ---------------------------------------- total: 12.810000sec user system total real parse in order 6.320000 0.040000 6.360000 ( 6.394460) parse 6.040000 0.040000 6.080000 ( 6.099738) =end yard-0.8.7.3/benchmarks/format_args.rb0000644000004100000410000000234112261240652017624 0ustar www-datawww-datarequire "benchmark" require 'lib/yard' def format_args_regex(object) if object.signature object.signature[/#{Regexp.quote object.name.to_s}\s*(.*)/, 1] else "" end end def format_args_parameters(object) if !object.parameters.empty? args = object.parameters.map {|n, v| v ? "#{n} = #{v}" : n.to_s }.join(", ") "(#{args})" else "" end end YARD::Registry.load $object = YARD::Registry.at('YARD::Generators::Base#G') log.puts "regex: " + format_args_regex($object) log.puts "params: " + format_args_parameters($object) log.puts TIMES = 100_000 Benchmark.bmbm do |x| x.report("regex") { TIMES.times { format_args_regex($object) } } x.report("parameters") { TIMES.times { format_args_parameters($object) } } end =begin LAST RUN Jun 23 2008 regex: (generator, opts = {}) params: (generator, opts = {}) Rehearsal ---------------------------------------------- regex 1.270000 0.020000 1.290000 ( 1.294558) parameters 0.690000 0.000000 0.690000 ( 0.693324) ------------------------------------- total: 1.980000sec user system total real regex 1.260000 0.010000 1.270000 ( 1.268214) parameters 0.670000 0.000000 0.670000 ( 0.679114) =end yard-0.8.7.3/checksums.yaml.gz0000444000004100000410000000041612261240652016145 0ustar www-datawww-dataDtRe9RdA D>E_'<<|N JcC Nz/^f>+癝.ݳfP  2%+-.y7&tb֒cmpB%=!qp`ոai 39$$-`7ZSz'1E?1h O܎M$]qbMYx)˘mԑ{.@]lFM&R(l\P}6Ңyard-0.8.7.3/LEGAL0000644000004100000410000000564312261240652013435 0ustar www-datawww-dataLEGAL NOTICE INFORMATION ------------------------ All the files in this distribution are covered under either the MIT license (see the file LICENSE) except some files mentioned below. lib/parser/ruby/legacy/ruby_lex.rb: This file is under the Ruby license. YARD uses a modified version of it. Ruby is copyrighted free software by Yukihiro Matsumoto . You can redistribute it and/or modify it under either the terms of the GPL version 2 (see the file GPL), or the conditions below: 1. You may make and give away verbatim copies of the source form of the software without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may modify your copy of the software in any way, provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or by allowing the author to include your modifications in the software. b) use the modified software only within your corporation or organization. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 3. You may distribute the software in object code or binary form, provided that you do at least ONE of the following: a) distribute the binaries and library files of the software, together with instructions (in the manual page or equivalent) on where to get the original distribution. b) accompany the distribution with the machine-readable source of the software. c) give non-standard binaries non-standard names, with instructions on where to get the original software distribution. d) make other distribution arrangements with the author. 4. You may modify and include the part of the software into any other software (possibly commercial). But some files in the distribution are not written by the author, so that they are not under these terms. For the list of those files and their copying conditions, see the file LEGAL. 5. The scripts and library files supplied as input to or produced as output from the software do not automatically fall under the copyright of the software, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this software. 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. yard-0.8.7.3/README.md0000644000004100000410000007011312261240652014137 0ustar www-datawww-data# YARD: Yay! A Ruby Documentation Tool **Homepage**: http://yardoc.org **IRC**: [irc.freenode.net / #yard](irc://irc.freenode.net/yard) **Git**: http://github.com/lsegal/yard **Author**: Loren Segal **Contributors**: http://github.com/lsegal/yard/contributors **Copyright**: 2007-2013 **License**: MIT License **Latest Version**: 0.8.7.3 **Release Date**: November 1st 2013 ## Synopsis YARD is a documentation generation tool for the Ruby programming language. It enables the user to generate consistent, usable documentation that can be exported to a number of formats very easily, and also supports extending for custom Ruby constructs such as custom class level definitions. Below is a summary of some of YARD's notable features. ## Feature List **1. RDoc/SimpleMarkup Formatting Compatibility**: YARD is made to be compatible with RDoc formatting. In fact, YARD does no processing on RDoc documentation strings, and leaves this up to the output generation tool to decide how to render the documentation. **2. Yardoc Meta-tag Formatting Like Python, Java, Objective-C and other languages**: YARD uses a '@tag' style definition syntax for meta tags alongside regular code documentation. These tags should be able to happily sit side by side RDoc formatted documentation, but provide a much more consistent and usable way to describe important information about objects, such as what parameters they take and what types they are expected to be, what type a method should return, what exceptions it can raise, if it is deprecated, etc.. It also allows information to be better (and more consistently) organized during the output generation phase. You can find a list of tags in the {file:docs/Tags.md#taglist Tags.md} file. YARD also supports an optional "types" declarations for certain tags. This allows the developer to document type signatures for ruby methods and parameters in a non intrusive but helpful and consistent manner. Instead of describing this data in the body of the description, a developer may formally declare the parameter or return type(s) in a single line. Consider the following method documented with YARD formatting: # Reverses the contents of a String or IO object. # # @param [String, #read] contents the contents to reverse # @return [String] the contents reversed lexically def reverse(contents) contents = contents.read if contents.respond_to? :read contents.reverse end With the above @param tag, we learn that the contents parameter can either be a String or any object that responds to the 'read' method, which is more powerful than the textual description, which says it should be an IO object. This also informs the developer that they should expect to receive a String object returned by the method, and although this may be obvious for a 'reverse' method, it becomes very useful when the method name may not be as descriptive. **3. Custom Constructs and Extensibility of YARD**: YARD is designed to be extended and customized by plugins. Take for instance the scenario where you need to document the following code: class List # Sets the publisher name for the list. cattr_accessor :publisher end This custom declaration provides dynamically generated code that is hard for a documentation tool to properly document without help from the developer. To ease the pains of manually documenting the procedure, YARD can be extended by the developer to handle the `cattr_accessor` construct and automatically create an attribute on the class with the associated documentation. This makes documenting external API's, especially dynamic ones, a lot more consistent for consumption by the users. YARD is also designed for extensibility everywhere else, allowing you to add support for new programming languages, new data structures and even where/how data is stored. **4. Raw Data Output**: YARD also outputs documented objects as raw data (the dumped Namespace) which can be reloaded to do generation at a later date, or even auditing on code. This means that any developer can use the raw data to perform output generation for any custom format, such as YAML, for instance. While YARD plans to support XHTML style documentation output as well as command line (text based) and possibly XML, this may still be useful for those who would like to reap the benefits of YARD's processing in other forms, such as throwing all the documentation into a database. Another useful way of exploiting this raw data format would be to write tools that can auto generate test cases, for example, or show possible unhandled exceptions in code. **5. Local Documentation Server**: YARD can serve documentation for projects or installed gems (similar to `gem server`) with the added benefit of dynamic searching, as well as live reloading. Using the live reload feature, you can document your code and immediately preview the results by refreshing the page; YARD will do all the work in re-generating the HTML. This makes writing documentation a much faster process. ## Installing To install YARD, use the following command: $ gem install yard (Add `sudo` if you're installing under a POSIX system as root) Alternatively, if you've checked the source out directly, you can call `rake install` from the root project directory. **Important Note for Debian/Ubuntu users:** there's a possible chance your Ruby install lacks RDoc, which is occasionally used by YARD to convert markup to HTML. If running `which rdoc` turns up empty, install RDoc by issuing: $ sudo apt-get install rdoc ## Usage There are a couple of ways to use YARD. The first is via command-line, and the second is the Rake task. **1. yard Command-line Tool** YARD comes packaged with a executable named `yard` which can control the many functions of YARD, including generating documentation, graphs running the YARD server, and so on. To view a list of available YARD commands, type: $ yard --help Plugins can also add commands to the `yard` executable to provide extra functionality. ### Generating Documentation The `yardoc` executable is a shortcut for `yard doc`. The most common command you will probably use is `yard doc`, or `yardoc`. You can type `yardoc --help` to see the options that YARD provides, but the easiest way to generate docs for your code is to simply type `yardoc` in your project root. This will assume your files are located in the `lib/` directory. If they are located elsewhere, you can specify paths and globs from the commandline via: $ yardoc 'lib/**/*.rb' 'app/**/*.rb' ...etc... The tool will generate a `.yardoc` file which will store the cached database of your source code and documentation. If you want to re-generate your docs with another template you can simply use the `--use-cache` (or -c) option to speed up the generation process by skipping source parsing. YARD will by default only document code in your public visibility. You can document your protected and private code by adding `--protected` or `--private` to the option switches. In addition, you can add `--no-private` to also ignore any object that has the `@private` meta-tag. This is similar to RDoc's ":nodoc:" behaviour, though the distinction is important. RDoc implies that the object with :nodoc: would not be documented, whereas YARD still recommends documenting private objects for the private API (for maintainer/developer consumption). You can also add extra informative files (README, LICENSE) by separating the globs and the filenames with '-'. $ yardoc 'app/**/*.rb' - README LICENSE FAQ If no globs precede the '-' argument, the default glob (`lib/**/*.rb`) is used: $ yardoc - README LICENSE FAQ Note that the README file can be specified with its own `--readme` switch. You can also add a `.yardopts` file to your project directory which lists the switches separated by whitespace (newlines or space) to pass to yardoc whenever it is run. A full overview of the `.yardopts` file can be found in {YARD::CLI::Yardoc}. ### Queries The `yardoc` tool also supports a `--query` argument to only include objects that match a certain data or meta-data query. The query syntax is Ruby, though a few shortcuts are available. For instance, to document only objects that have an "@api" tag with the value "public", all of the following syntaxes would give the same result: --query '@api.text == "public"' --query 'object.has_tag?(:api) && object.tag(:api).text == "public"' --query 'has_tag?(:api) && tag(:api).text == "public"' Note that the "@tag" syntax returns the first tag named "tag" on the object. To return the array of all tags named "tag", use "@@tag". Multiple `--query` arguments are allowed in the command line parameters. The following two lines both check for the existence of a return and param tag: --query '@return' --query '@param' --query '@return && @param' For more information about the query syntax, see the {YARD::Verifier} class. **2. Rake Task** The second most obvious is to generate docs via a Rake task. You can do this by adding the following to your `Rakefile`: YARD::Rake::YardocTask.new do |t| t.files = ['lib/**/*.rb', OTHER_PATHS] # optional t.options = ['--any', '--extra', '--opts'] # optional end both the `files` and `options` settings are optional. `files` will default to `lib/**/*.rb` and `options` will represents any options you might want to add. Again, a full list of options is available by typing `yardoc --help` in a shell. You can also override the options at the Rake command-line with the OPTS environment variable: $ rake yard OPTS='--any --extra --opts' **3. `yri` RI Implementation** The yri binary will use the cached .yardoc database to give you quick ri-style access to your documentation. It's way faster than ri but currently does not work with the stdlib or core Ruby libraries, only the active project. Example: $ yri YARD::Handlers::Base#register $ yri File.relative_path Note that class methods must not be referred to with the "::" namespace separator. Only modules, classes and constants should use "::". You can also do lookups on any installed gems. Just make sure to build the .yardoc databases for installed gems with: $ sudo yard gems If you don't have sudo access, it will write these files to your `~/.yard` directory. `yri` will also cache lookups there. **4. `yard server` Documentation Server** The `yard server` command serves documentation for a local project or all installed RubyGems. To serve documentation for a project you are working on, simply run: $ yard server And the project inside the current directory will be parsed (if the source has not yet been scanned by YARD) and served at [http://localhost:8808](http://localhost:8808). ### Live Reloading If you want to serve documentation on a project while you document it so that you can preview the results, simply pass `--reload` (`-r`) to the above command and YARD will reload any changed files on each request. This will allow you to change any documentation in the source and refresh to see the new contents. ### Serving Gems To serve documentation for all installed gems, call: $ yard server --gems This will also automatically build documentation for any gems that have not been previously scanned. Note that in this case there will be a slight delay between the first request of a newly parsed gem. **5. `yard graph` Graphviz Generator** You can use `yard graph` to generate dot graphs of your code. This, of course, requires [Graphviz](http://www.graphviz.org) and the `dot` binary. By default this will generate a graph of the classes and modules in the best UML2 notation that Graphviz can support, but without any methods listed. With the `--full` option, methods and attributes will be listed. There is also a `--dependencies` option to show mixin inclusions. You can output to stdout or a file, or pipe directly to `dot`. The same public, protected and private visibility rules apply to `yard graph`. More options can be seen by typing `yard graph --help`, but here is an example: $ yard graph --protected --full --dependencies ## Changelog - **November.1.13**: 0.8.7.3 release - Handle Unicode method/class/file names in server URL encoding (lsegal/rubydoc.info#69). - Style keyword style hashes with same symbol color in code highlighting (#707). - Fix broken JS when visiting docs in file:// scheme (#706). - Add support for new AsciiDoc file extensions (#704). - Fix issues where non-Ruby code blocks would not display in Ruby 2 (#702). - Add support for extra Ruby 2 symbol types in Ripper (#701). - Ensure config directory exists before saving config file (#700). - **September.18.13**: 0.8.7.2 release - Disallow absolute URLs when using frame anchor support. - Support casted functions in CRuby method declarations (#697) - **September.11.13**: 0.8.7.1 release - Fix potential XSS issue with frame anchor support. - Add support for gettext 3.x gem. - **July.26.13**: 0.8.7 release - Added `--hide-api API` option to hide objects with a given `@api` tag (#685). - Added "Returns ...." prefix to summary when a lone @return tag is used. - Fixed issue that caused ref tags to be added to a docstring twice (#678). - Fixed formatting issue in docstring summaries (#686) - **June.27.13**: 0.8.6.2 release - Fixed issue where `yard graph` was not displaying methods - **April.14.13**: 0.8.6.1 release - Fixed broken links in File menu on default HTML template - Added --layout switch to `yard display` to wrap output in layout template. - See {file:docs/WhatsNew.md} for more information on added features. - **April.13.13**: 0.8.6 release - Various fixes and improved Ruby 2.x compatibility support - Added support for `asciidoc` markup type - Added `yard markups` command to list available markup types - Added `yard display` command to display and format an individual object - See {file:docs/WhatsNew.md} for more information on added features. - **February.26.13**: 0.8.5.2 release - Support new keyword argument syntax in method signatures (Ruby 2.x) - **February.25.13**: 0.8.5.1 release - Fix `yard diff` of gem files with RubyGems 2.x - **February.24.13**: 0.8.5 release - Basic support for Ruby 2.0 (fix compat issues in RDoc 4.0, RubyGems 2.0) - Add CSS styling for tables in default HTML template - **February.5.13**: 0.8.4.1 release - Fix regression that broke loading of existing yardoc dbs (#648) - **February.4.13**: 0.8.4 release - Add `-B/--bind` switch to yard server (#593, #608) - Add CodeObjects::Base#title for plugins to customize how object links display (#646) - Disable linking objects filtered out by verifiers (#645) - Allow macro expansion on class methods (#632) - Expand newly attached macro on first DSL method call (#631) - Disable RubyGems plugin in Ruby 2.0 (#627) - Fix line range for class/module node bodies (#626) - Search extended modules for attached DSL macros (#553) - **October.14.12**: 0.8.3 release - Add `--non-transitive-tag` to disable tag transitivity (#571) - Support --db inside .yardopts for graph/server commands (#583, #586) - Fix handling for =begin/=end docstrings (#577, #578) - Parser only sorts file lists when a glob is provided (#572) - Fix formatting in `{include:Object#method}` syntax (#569) - Fix @option tag inside of module functions (#563) - Fix to `--api` and `--no-api` support (#559) - Fix class nesting issues when path starts with "::" (#552) - **June.9.12**: 0.8.2.1 release - Fix a set of regressions in yard server search and dynamic generation - **June.7.12**: 0.8.2 release - Added progress style output in tty terminals - Embedded mixins should ignore methods defined on module (#539) - Fixed permalinks for embedded mixins in `yard server` (#540) - Improve parsing in CRuby code (#543) - Ensure Registry.resolve picks module when parsing mixins (#545) - Fixed regression that caused various commands to not show output (#548) - Respect current visibility when parsing class conditions (#551) - **May.2.12**: 0.8.1 release - Added `--[no-]api` switch to generate docs for API sets (see {file:docs/WhatsNew.md} for details) (#532) - The `yard list` command now uses cache by default (#533) - Fix `yardoc` generating incorrectly named method list file (#528) - Fix HTML output occasionally showing trailing mdash on options list (#522) - **April.30.12**: 0.8.0 release - See {file:docs/WhatsNew.md} for a list of added features - Over 20 bug fixes: - Properly filter hidden setter/getter attributes (#394) - Fix test failures in Linux environments (#397, #472, #473, #512, #513) - Fix attribute inheritance and @private (#432) - Fix attribute parsing (#435) - Allow aliases for attributes (#436) - Fix namespace fetching in `handle_alias()` (#437) - Fix overwritten attributes marked as inherited (#442) - Fix documenting constants defined from C code with `rb_define_const()` (#443) - Do not escape snippets twice (#445) - Ajax method/class search should not fire when a non-printable character is pressed (#446) - Fix yard server crashing when RDoc is not installed (#456) - Fix tags ignored when `(see #foo)` is used (#457) - Fix three "Returns" for two `@overload` tags (#458) - Do not auto-detect DSL methods as method objects if parameter name is not a valid method name (#464) - Fix attaching of macros to Object (#465) - Fix handling of `%w()` source in `[]/[]=` parsed context. (#461, pull in #468) - Don't add default `@return` if `@overload` has `@return`. (#458, pull in #469) - Don't discard tags by (see ...). (#457, pull in #470) - Fix constants listed as inherited when overwritten (#474) - Fix `yardoc --asset` behaving differently on first and subsequent calls. (#477) - `!!!lang` code blocks should set the lang in `
            `'s class. (#478, #479)
                  - Fix "File List" search tab error. (#502)
                  - Fix search bar not redirecting to method page. (#509)
                  - Fix server returning exception message bodies as String (#518)
            
            - **January.31.12**: 0.7.5 release
                - Various minor bug fixes
            
            - **December.2.11**: 0.7.4 release
                - Redcarpet is now the default Markdown formatting library. GFM now works out-of-box (#404)
                - Fix server side searching for elements that are marked private (#420)
                - Add 'textile_strict' and 'pre' markup types, reorganize text and none (#416)
                - Improve encoding line detection (#415)
                - Add support for `rb_define_alias` in CRuby code (#413)
                - Fix rendering of some keywords in source view (#410)
                - Add support for RDoc 3.10+ (#406, #407)
                - Fix typewriter text being processed in code blocks (#403)
                - Improve support for has_rdoc in RubyGems 1.8.x (#401)
                - See the {file:docs/WhatsNew.md} document for details on added features
            
            - **October.15.11**: 0.7.3 release
                - Improve support for parsing under Ruby 1.9.2p290 and 1.9.3 (#365, #370)
                - Add support for SWIG generated CRuby code (#369)
                - Add support for `rb_define_attr` calls in CRuby code (#362)
                - Handle file pointers in CRuby code (#358)
            
            - **June.14.11**: 0.7.2 release
                - Fix `yard --help` not showing proper output
                - YARD now expands path to `.yardoc` file in daemon mode for server (#328)
                - Fix `@overload` tag linking to wrong method (#330)
                - Fix incorrect return type when using `@macro` (#334)
                - YARD now requires 'thread' to support RubyGems 1.7+ (#338)
                - Fix bug in constant documentation when using `%w()` (#348)
                - Fix YARD style URL links when using autolinking markdown (#353)
            
            - **May.18.11**: 0.7.1 release
                - Fixes a bug in `yard server` not displaying class list properly.
            
            - **May.17.11**: 0.7.0 release
                - See the {file:docs/WhatsNew.md} document for details on added features
                - Make sure that Docstring#line_range is filled when possible (#243)
                - Set #verifier in YardocTask (#282)
                - Parse BOM in UTF-8 files (#288)
                - Fix instance attributes not showing up in method list (#302)
                - Fix rendering of %w() literals in constants (#306)
                - Ignore keyboard shortcuts when an input is active (#312)
                - And more...
            
            - **April.14.11**: 0.6.8 release
                - Fix regression in RDoc 1.x markup loading
                - Fix regression in loading of markup libraries for `yard server`
            
            - **April.6.11**: 0.6.7 release
                - Fix has_rdoc gem specification issue with new RubyGems plugin API (oops!)
            
            - **April.6.11**: 0.6.6 release
                - Fix error message when RDoc is not present (#270)
                - Add markup type 'none' to perform basic HTML translation (fallback when RDoc is not present)
                - Add support for RubyGems 1.7.x (#272)
                - Fix rendering of `{url description}` syntax when description contains newline
            
            - **March.13.11**: 0.6.5 release
                - Support `ripper` gem in Ruby 1.8.7
                - Upgrade jQuery to 1.5.1
                - Fix handling of alias statements with quoted symbols (#262)
                - Add CSS styles (#260)
                - Unhandled exception in YARD::Handlers::Ruby::MixinHandler indexing documentation for eventmachine (#248)
                - Splice any alias references on method re-definitions into separate methods (#247)
                - Fix "yard graph" (#245)
                - Don't process ++ typewriter text inside of HTML attributes (#244)
                - Prioritize loading of Kramdown before Maruku (#241)
                - Skip shebang encoding in docstrings (#238)
                - Fix truncation of references in @deprecated (#232)
                - Show @api private note when no other tags are present (#231)
                - Detect docstrings starting with "##" as `Docstring#hash_flag` (#230)
                - Remove trailing whitespace from freeform tags (#229)
                - Fix line through for deprecated methods (#225)
                - Mistake in Tags.md (#223)
                - Improve database storage by being more efficient with filesystem usage (#222)
                - Make Registry thread local (#221)
                - Support `private_constant` class method for 1.9.3 (#219)
                - Do not assume RDoc is installed (#214)
            
            - **December.21.10**: 0.6.4 release
                - Fix yri tool crashing with new Config class (gh-217)
                - Fix support for ::TopLevelConstants (gh-216)
                - YARD's test suite is now RSpec2 compatible (gh-215)
                - Improved documentation for YARD::Server features (gh-207)
                - Fix displaying of collaped method summary lists (gh-204)
                - Fix automatic loading of markup providers (gh-206)
                - Fix keyboard shortcuts for Chrome (gh-203)
                - Disallow `extend self` inside of a class (gh-202)
                - Constants now recognized in C extensions (gh-201)
            
            - **November.21.10**: 0.6.3 release
                - Fixed regression that caused `yardoc --markup` to silently exit
            
            - **November.15.10**: 0.6.2 release
                - **Plugins no longer automatically load, use `--plugin` to load a plugin**
                - Added YARD::Config and ~/.yard/config YAML configuration file
                - Added `yard config` command to view/edit YARD configuration file
                - Fixes for YARD in 1.8.6 (gh-178)
                - Various HTML template adjustments and fixes (gh-198,199,200)
                - Improved `yard server -m` multi-project stability (gh-193)
                - Fixed handling of `yardoc --no-private` with missing class definitions (gh-197)
                - Added support for constants defined in C extensions (gh-177)
                - Added support for Structs defined as "Klass = Struct.new(...)" (gh-187)
                - Improved parsing support for third-party gems (gh-174,180)
                - Improved support for JRuby 1.6.4+. YARD now passes all specs in JRuby (gh-185)
                - Improved YARD documentation (gh-172,191,196)
            
            - **September.06.10**: 0.6.1 release
                - Fixed TOC showing on top of class/method list in no-frames view
                - A message now displays when running `yard server` with Rack/Mongrel installed
                - Improved performance of JS inline search for large class/method lists
                - Improved link titles for relative object links
                - Removed `String#camelcase` and `String#underscore` for better Rails compat.
                - Fixed support for loading .yardoc files under Windows
                - Fixed inheritance tree arrows not displaying in certain environments
            
            - **August.29.10**: 0.6.0 release
                - Added dynamic local documentation server
                - Added @group/@endgroup declarations to organize methods into groups
                - Added `yard` executable to serve as main CLI tool with pluggable commands
                - Added `--asset` switch to `yardoc` to copy files/dirs to output dir
                - Added ability to register/manipulate tags via CLI (`--tag`, etc.)
                - Added `yard diff` command
                - Added statistics to `yardoc` output (and `yard stats` command)
                - Added Javascript generated Table of Contents to file pages
                - Updated various APIs
                - Removed `yard-graph` executable
                - See more changes in the {file:docs/WhatsNew.md what's new document}
            
            - **June.22.10**: 0.5.8 release
                - Merge fix from 0.6 branch for --no-private visibility checking
            
            - **June.21.10**: 0.5.7 release
                - Fixed visibility flag parsing in `yardoc`
                - Updated Parser Architecture documentation with new SourceParser API
                - Improved Registry documentation for new load commands
                - Fix loading of .yardoc file as cache (and preserving aliases)
                - Fix "lib" directory missing when running YARD on installed gems
            
            - **June.12.10**: 0.5.6 release
                - Bug fixes for RubyGems plugin, `has_rdoc=false` should now work
                - New API for registering custom parsers. See {file:docs/WhatsNew.md}
            
            - **May.22.10**: 0.5.5 release
                - Various bug fixes
            
            - **March.22.10**: 0.5.4 release
                - See {file:docs/WhatsNew.md what's new document} for changes
            
            - **January.11.10**: 0.5.3 release
                - See {file:docs/WhatsNew.md what's new document} for changes
            
            - **December.16.09**: 0.5.2 release
                - See {file:docs/WhatsNew.md what's new document} for changes
            
            - **December.15.09**: 0.5.1 release
                - See {file:docs/WhatsNew.md what's new document} for changes
            
            - **December.13.09**: 0.5.0 release
                - See {file:docs/WhatsNew.md what's new document} for changes
            
            - **November.15.09**: 0.4.0 release
                - Added new templating engine based on [tadpole](http://github.com/lsegal/tadpole)
                - Added YARD queries (`--query` CLI argument to yardoc)
                - Greatly expanded YARD documentation
                - Added plugin support
                - New `@abstract` and `@private` tags
                - Changed default rake task to `rake yard`
                - Read about changes in {file:docs/WhatsNew.md}
            
            - **August.13.09**: 0.2.3.5 release
                - Minor bug fixes.
            
            - **August.07.09**: 0.2.3.4 release
                - Minor bug fixes.
            
            - **July.26.09**: 0.2.3.3 release
                - Minor bug fixes.
            
            - **July.06.09**: 0.2.3.2 release
                - Fix Textile hard-break issues
                - Add description for @see tag to use as link title in HTML docs.
                - Add --title CLI option to specify a title for HTML doc files.
                - Add custom.css file that can be overridden with various custom
                  styelsheet declarations. To use this, simply add `default/fulldoc/html/custom.css`
                  inside your code directory and use the `-t` template directory yardoc CLI
                  option to point to that template directory (the dir holding 'default').
                - Add support in `yardoc` CLI to specify extra files (formerly --files)
                  by appending "- extra files here" after regular source files. Example:
            
                        yardoc --private lib/**/*.rb - FAQ LICENSE
            
            - **Jun.13.09**: 0.2.3.1 release.
                - Add a RubyGems 1.3.2+ plugin to generate YARD documentation instead of
                  RDoc. To take advantage of this plugin, set `has_rdoc = 'yard'` in your
                  .gemspec file.
            
            - **Jun.07.09**: 0.2.3 release. See the {file:docs/WhatsNew.md} file for a
              list of important new features.
            
            - **Jun.16.08**: 0.2.2 release. This is the largest changset since yard's
              conception and involves a complete overhaul of the parser and API to make it
              more robust and far easier to extend and use for the developer.
            
            - **Feb.20.08**: 0.2.1 release.
            
            - **Feb.24.07**: Released 0.1a experimental version for testing. The goal here is
              to get people testing YARD on their code because there are too many possible
              code styles to fit into a sane amount of test cases. It also demonstrates the
              power of YARD and what to expect from the syntax (Yardoc style meta tags).
            
            
            ## Copyright
            
            YARD © 2007-2013 by [Loren Segal](mailto:lsegal@soen.ca). YARD is
            licensed under the MIT license except for some files which come from the
            RDoc/Ruby distributions. Please see the {file:LICENSE} and {file:LEGAL}
            documents for more information.
            yard-0.8.7.3/yard.gemspec0000644000004100000410000000213612261240652015164 0ustar  www-datawww-datarequire File.expand_path('../lib/yard/version', __FILE__)
            
            Gem::Specification.new do |s|
              s.name          = "yard"
              s.summary       = "Documentation tool for consistent and usable documentation in Ruby."
              s.description   = <<-eof
                YARD is a documentation generation tool for the Ruby programming language.
                It enables the user to generate consistent, usable documentation that can be
                exported to a number of formats very easily, and also supports extending for
                custom Ruby constructs such as custom class level definitions.
              eof
              s.version       = YARD::VERSION
              s.date          = Time.now.strftime('%Y-%m-%d')
              s.author        = "Loren Segal"
              s.email         = "lsegal@soen.ca"
              s.homepage      = "http://yardoc.org"
              s.platform      = Gem::Platform::RUBY
              s.files         = Dir.glob("{docs,bin,lib,spec,templates,benchmarks}/**/*") +
                ['LICENSE', 'LEGAL', 'README.md', 'Rakefile', '.yardopts', __FILE__]
              s.require_paths = ['lib']
              s.executables   = ['yard', 'yardoc', 'yri']
              s.has_rdoc      = 'yard'
              s.rubyforge_project = 'yard'
              s.license = 'MIT' if s.respond_to?(:license=)
            end