yard-0.9.12/0000755000004100000410000000000013206751010012565 5ustar www-datawww-datayard-0.9.12/Rakefile0000755000004100000410000000203413206751010014234 0ustar www-datawww-data# frozen_string_literal: true require 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'] desc "Publish gem" task :publish do ver = ENV['VERSION'] raise "missing VERSION=x.y.z" if ver.nil? || ver.empty? if ver < YARD::VERSION raise "invalid version `#{ver}' (must be >= `#{YARD::VERSION}')" end file = "release-v#{ver}.tar.gz" cmd = "bundle exec samus" sh "#{cmd} build #{ver} && #{cmd} publish #{file} && rm #{file}" end desc "Builds the gem" task :gem do sh "gem build yard.gemspec" end desc "Installs the gem" task :install => :gem do sh "gem install yard-#{YARD::VERSION}.gem --no-document" end begin require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) rescue LoadError nil # noop end task :rubocop do sh "rubocop" end task :default => [:rubocop, :spec] YARD::Rake::YardocTask.new do |t| t.options += ['--title', "YARD #{YARD::VERSION} Documentation"] end yard-0.9.12/bin/0000755000004100000410000000000013206751010013335 5ustar www-datawww-datayard-0.9.12/bin/yard0000755000004100000410000000054213206751010014223 0ustar www-datawww-data#!/usr/bin/env ruby # frozen_string_literal: true # 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 $LOAD_PATH.unshift(File.join(File.dirname(File.expand_path(path)), '..', 'lib')) require 'yard' YARD::CLI::CommandParser.run(*ARGV) yard-0.9.12/bin/yri0000755000004100000410000000053013206751010014064 0ustar www-datawww-data#!/usr/bin/env ruby # frozen_string_literal: true # 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 $LOAD_PATH.unshift(File.join(File.dirname(File.expand_path(path)), '..', 'lib')) require 'yard' YARD::CLI::YRI.run(*ARGV) yard-0.9.12/bin/yardoc0000755000004100000410000000053313206751010014545 0ustar www-datawww-data#!/usr/bin/env ruby # frozen_string_literal: true # 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 $LOAD_PATH.unshift(File.join(File.dirname(File.expand_path(path)), '..', 'lib')) require 'yard' YARD::CLI::Yardoc.run(*ARGV) yard-0.9.12/templates/0000755000004100000410000000000013206751010014563 5ustar www-datawww-datayard-0.9.12/templates/default/0000755000004100000410000000000013206751010016207 5ustar www-datawww-datayard-0.9.12/templates/default/tags/0000755000004100000410000000000013206751010017145 5ustar www-datawww-datayard-0.9.12/templates/default/tags/html/0000755000004100000410000000000013206751010020111 5ustar www-datawww-datayard-0.9.12/templates/default/tags/html/index.erb0000755000004100000410000000005313206751010021713 0ustar www-datawww-data
<%= yieldall %>
yard-0.9.12/templates/default/tags/html/see.erb0000755000004100000410000000031713206751010021363 0ustar www-datawww-data<% if object.has_tag?(:see) %>

See Also:

<% end %>yard-0.9.12/templates/default/tags/html/example.erb0000755000004100000410000000060113206751010022236 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.9.12/templates/default/tags/html/overload.erb0000755000004100000410000000104613206751010022422 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.9.12/templates/default/tags/html/tag.erb0000755000004100000410000000142413206751010021362 0ustar www-datawww-data

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

yard-0.9.12/templates/default/tags/html/option.erb0000755000004100000410000000161013206751010022114 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.sub(/^\*+|:$/, '') } %> <% next if tags.empty? %>

Options Hash (<%= param %>):

<% end %> <% end %> yard-0.9.12/templates/default/tags/text/0000755000004100000410000000000013206751010020131 5ustar www-datawww-datayard-0.9.12/templates/default/tags/text/index.erb0000755000004100000410000000002013206751010021725 0ustar www-datawww-data<%= yieldall %> yard-0.9.12/templates/default/tags/text/see.erb0000755000004100000410000000034213206751010021401 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.9.12/templates/default/tags/text/example.erb0000755000004100000410000000043013206751010022256 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.9.12/templates/default/tags/text/overload.erb0000755000004100000410000000057313206751010022446 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.9.12/templates/default/tags/text/tag.erb0000755000004100000410000000070513206751010021403 0ustar www-datawww-data<% title = (defined?(@label) && @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.9.12/templates/default/tags/text/option.erb0000755000004100000410000000115213206751010022135 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.sub(/^\*+|:$/, '') } %> <% 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.9.12/templates/default/tags/setup.rb0000755000004100000410000000252213206751010020636 0ustar www-datawww-data# frozen_string_literal: true def 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.tr('.', '_').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 = opts[:no_names] ? true : false @no_types = opts[:no_types] ? true : false @name = name out = erb('tag') @no_names = nil @no_types = nil out end def create_tag_methods(tags) tags.each do |tag| tag_meth = tag.to_s.tr('.', '_') 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.9.12/templates/default/docstring/0000755000004100000410000000000013206751010020203 5ustar www-datawww-datayard-0.9.12/templates/default/docstring/html/0000755000004100000410000000000013206751010021147 5ustar www-datawww-datayard-0.9.12/templates/default/docstring/html/index.erb0000755000004100000410000000012713206751010022753 0ustar www-datawww-data
<%= yieldall %>
yard-0.9.12/templates/default/docstring/html/returns_void.erb0000755000004100000410000000011013206751010024357 0ustar www-datawww-data

This method returns an undefined value.

yard-0.9.12/templates/default/docstring/html/todo.erb0000755000004100000410000000022013206751010022603 0ustar www-datawww-data<% object.tags(:todo).each do |tag| %>
TODO: <%= htmlify_line tag.text %>
<% end %> yard-0.9.12/templates/default/docstring/html/note.erb0000755000004100000410000000022313206751010022606 0ustar www-datawww-data<% object.tags(:note).each do |tag| %>
Note: <%= htmlify_line tag.text %>
<% end %> yard-0.9.12/templates/default/docstring/html/abstract.erb0000755000004100000410000000021413206751010023444 0ustar www-datawww-data
This <%= object.type %> is abstract. <%= htmlify_line object.tag(:abstract).text %>
yard-0.9.12/templates/default/docstring/html/deprecated.erb0000755000004100000410000000016113206751010023742 0ustar www-datawww-data
Deprecated. <%= htmlify_line object.tag(:deprecated).text %>
yard-0.9.12/templates/default/docstring/html/private.erb0000755000004100000410000000032313206751010023314 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.9.12/templates/default/docstring/html/text.erb0000755000004100000410000000003713206751010022630 0ustar www-datawww-data<%= htmlify(docstring_text) %> yard-0.9.12/templates/default/docstring/text/0000755000004100000410000000000013206751010021167 5ustar www-datawww-datayard-0.9.12/templates/default/docstring/text/index.erb0000755000004100000410000000002113206751010022764 0ustar www-datawww-data <%= yieldall %> yard-0.9.12/templates/default/docstring/text/returns_void.erb0000755000004100000410000000007613206751010024412 0ustar www-datawww-data<%= indent(wrap("This method returns an undefined value.")) %>yard-0.9.12/templates/default/docstring/text/todo.erb0000755000004100000410000000013213206751010022625 0ustar www-datawww-data<% object.tags(:todo).each do |tag| %> <%= indent(wrap("TODO: #{tag.text}")) %> <% end %>yard-0.9.12/templates/default/docstring/text/note.erb0000755000004100000410000000013213206751010022625 0ustar www-datawww-data<% object.tags(:note).each do |tag| %> <%= indent(wrap("Note: #{tag.text}")) %> <% end %>yard-0.9.12/templates/default/docstring/text/abstract.erb0000755000004100000410000000010013206751010023456 0ustar www-datawww-data<%= indent(wrap("Abstract. #{object.tag(:abstract).text}")) %> yard-0.9.12/templates/default/docstring/text/deprecated.erb0000755000004100000410000000010413206751010023757 0ustar www-datawww-data<%= indent(wrap("Deprecated. #{object.tag(:deprecated).text}")) %> yard-0.9.12/templates/default/docstring/text/private.erb0000755000004100000410000000010613206751010023333 0ustar www-datawww-data<%= indent(wrap("This #{object.type} is part of a private API.")) %> yard-0.9.12/templates/default/docstring/text/text.erb0000755000004100000410000000006013206751010022644 0ustar www-datawww-data<%= indent wrap(h(docstring_text.strip), 68) %> yard-0.9.12/templates/default/docstring/setup.rb0000755000004100000410000000237313206751010021700 0ustar www-datawww-data# frozen_string_literal: true def 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])/, &:downcase) text = "Returns #{text}" unless text.empty? || text =~ /^\s*return/i text = text.gsub(/\A([a-z])/, &:upcase) end text.strip end yard-0.9.12/templates/default/root/0000755000004100000410000000000013206751010017172 5ustar www-datawww-datayard-0.9.12/templates/default/root/html/0000755000004100000410000000000013206751010020136 5ustar www-datawww-datayard-0.9.12/templates/default/root/html/setup.rb0000755000004100000410000000007713206751010021632 0ustar www-datawww-data# frozen_string_literal: true include T('default/module/html') yard-0.9.12/templates/default/root/dot/0000755000004100000410000000000013206751010017760 5ustar www-datawww-datayard-0.9.12/templates/default/root/dot/child.erb0000755000004100000410000000013313206751010021535 0ustar www-datawww-data<% if inner = yieldall.gsub("\n", '') %> Root [label="{<%= inner %>}" rank=sink]; <% end %>yard-0.9.12/templates/default/root/dot/setup.rb0000755000004100000410000000014113206751010021444 0ustar www-datawww-data# frozen_string_literal: true include T('default/module/dot') def format_path(_object) "" end yard-0.9.12/templates/default/method_details/0000755000004100000410000000000013206751010021174 5ustar www-datawww-datayard-0.9.12/templates/default/method_details/html/0000755000004100000410000000000013206751010022140 5ustar www-datawww-datayard-0.9.12/templates/default/method_details/html/source.erb0000755000004100000410000000055513206751010024142 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.9.12/templates/default/method_details/html/method_signature.erb0000755000004100000410000000157513206751010026206 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.9.12/templates/default/method_details/html/header.erb0000755000004100000410000000012713206751010024065 0ustar www-datawww-data
<%= yieldall %>
yard-0.9.12/templates/default/method_details/text/0000755000004100000410000000000013206751010022160 5ustar www-datawww-datayard-0.9.12/templates/default/method_details/text/method_signature.erb0000755000004100000410000000046413206751010026222 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.9.12/templates/default/method_details/text/setup.rb0000755000004100000410000000033713206751010023653 0ustar www-datawww-data# frozen_string_literal: true def init super sections.last.pop end def format_object_title(object) title = "Method: #{object.name(true)}" title += " (#{object.namespace})" unless object.namespace.root? title end yard-0.9.12/templates/default/method_details/text/header.erb0000755000004100000410000000040513206751010024104 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.9.12/templates/default/method_details/setup.rb0000755000004100000410000000037113206751010022665 0ustar www-datawww-data# frozen_string_literal: true def 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.9.12/templates/default/module/0000755000004100000410000000000013206751010017474 5ustar www-datawww-datayard-0.9.12/templates/default/module/html/0000755000004100000410000000000013206751010020440 5ustar www-datawww-datayard-0.9.12/templates/default/module/html/inherited_methods.erb0000755000004100000410000000200513206751010024630 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.9.12/templates/default/module/html/pre_docstring.erb0000755000004100000410000000002113206751010023770 0ustar www-datawww-data

Overview

yard-0.9.12/templates/default/module/html/inherited_constants.erb0000755000004100000410000000063513206751010025210 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.9.12/templates/default/module/html/methodmissing.erb0000755000004100000410000000072413206751010024012 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.9.12/templates/default/module/html/method_details_list.erb0000755000004100000410000000050613206751010025156 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.9.12/templates/default/module/html/item_summary.erb0000755000004100000410000000365613206751010023662 0ustar www-datawww-data
  • <% if @item.tags(:overload).size == 1 %> <%= signature(@item.tag(:overload), true, false, !@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.9.12/templates/default/module/html/children.erb0000755000004100000410000000044313206751010022726 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.9.12/templates/default/module/html/method_summary.erb0000755000004100000410000000051113206751010024167 0ustar www-datawww-data<% if method_listing.size > 0 %> <% groups(method_listing) do |list, name| %>

    <%= name %> collapse

    <% end %> <% end %>yard-0.9.12/templates/default/module/html/inherited_attributes.erb0000755000004100000410000000117213206751010025357 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.9.12/templates/default/module/html/attribute_details.erb0000755000004100000410000000064413206751010024651 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.9.12/templates/default/module/html/box_info.erb0000755000004100000410000000232313206751010022740 0ustar www-datawww-data
    <% if CodeObjects::ClassObject === object && object.superclass %>
    Inherits:
    <%= linkify object.superclass %> <% if object.superclass.name != :BasicObject %>
    • <%= linkify P(:Object) %>
    • <% object.inheritance_tree.reverse.each_with_index do |obj, i| %> <% end %>
    show all <% end %>
    <% 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(", ") %>
    <% end %> <% end %> <% if (mixed_into = mixed_into(object)).size > 0 %>
    Included in:
    <%= mixed_into.sort_by {|o| o.path }.map {|o| linkify(o) }.join(", ") %>
    <% end %> <% unless object.root? %>
    Defined in:
    <%= erb(:defines) %>
    <% end %>
    yard-0.9.12/templates/default/module/html/header.erb0000755000004100000410000000056213206751010022370 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.9.12/templates/default/module/html/attribute_summary.erb0000755000004100000410000000040713206751010024716 0ustar www-datawww-data<% groups(attr_listing, "Attribute") do |list, name| %>

    <%= name %> collapse

    <% end %> yard-0.9.12/templates/default/module/html/defines.erb0000755000004100000410000000027313206751010022554 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.9.12/templates/default/module/html/constant_summary.erb0000755000004100000410000000062713206751010024550 0ustar www-datawww-data<% if constant_listing.size > 0 %>

    Constant Summary

    <% constant_listing.each do |cnst| %>
    <%= cnst.name %> = <%= yieldall :object => cnst %>
    <%= format_constant cnst.value %>
    <% end %>
    <% end %> yard-0.9.12/templates/default/module/text/0000755000004100000410000000000013206751010020460 5ustar www-datawww-datayard-0.9.12/templates/default/module/text/instance_meths_list.erb0000755000004100000410000000023213206751010025211 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.9.12/templates/default/module/text/extends.erb0000755000004100000410000000020713206751010022626 0ustar www-datawww-data<% if object.mixins(:class).size > 0 %> Extended by: ------------ <%= indent wrap(object.mixins(:class).join(", "), 68) %> <% end %>yard-0.9.12/templates/default/module/text/class_meths_list.erb0000755000004100000410000000021613206751010024514 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.9.12/templates/default/module/text/children.erb0000755000004100000410000000033013206751010022741 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.9.12/templates/default/module/text/includes.erb0000755000004100000410000000020713206751010022762 0ustar www-datawww-data<% if object.mixins(:instance).size > 0 %> Includes: --------- <%= indent wrap(object.mixins(:instance).join(", "), 68) %> <% end %>yard-0.9.12/templates/default/module/text/setup.rb0000755000004100000410000000051613206751010022152 0ustar www-datawww-data# frozen_string_literal: true def 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 } end yard-0.9.12/templates/default/module/text/header.erb0000755000004100000410000000012313206751010022401 0ustar www-datawww-data<%= title_align_right format_object_title(object) %> <%= yieldall %> <%= hr %> yard-0.9.12/templates/default/module/dot/0000755000004100000410000000000013206751010020262 5ustar www-datawww-datayard-0.9.12/templates/default/module/dot/info.erb0000755000004100000410000000111613206751010021711 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.9.12/templates/default/module/dot/child.erb0000755000004100000410000000012013206751010022033 0ustar www-datawww-data<%= format_path object %> [label="{<%= yieldall.gsub("\n", '') %>}" rank=sink]; yard-0.9.12/templates/default/module/dot/dependencies.erb0000755000004100000410000000021313206751010023401 0ustar www-datawww-data<% object.mixins(:instance).each do |obj| %> <%= format_path object %> -> <%= format_path obj %> [style=dotted arrowType=none]; <% end %>yard-0.9.12/templates/default/module/dot/setup.rb0000755000004100000410000000062613206751010021756 0ustar www-datawww-data# frozen_string_literal: true def 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") end yard-0.9.12/templates/default/module/dot/header.erb0000755000004100000410000000030213206751010022202 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.9.12/templates/default/module/setup.rb0000755000004100000410000001227213206751010021170 0ustar www-datawww-data# frozen_string_literal: true include 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) @mm = mms.find {|o| o.name == :method_missing && o.scope == :instance } erb(:methodmissing) if @mm end def method_listing(include_specials = true) return @smeths ||= method_listing.reject {|o| special_method?(o) } unless include_specials return @meths if defined?(@meths) && @meths @meths = object.meths(:inherited => false, :included => !options.embed_mixins.empty?) unless options.embed_mixins.empty? @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 defined?(@attrs) && @attrs @attrs = [] object.inheritance_tree(true).each do |superclass| next if superclass.is_a?(CodeObjects::Proxy) next if !options.embed_mixins.empty? && !options.embed_mixins_match?(superclass) [: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 defined?(@constants) && @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 object.inheritance_tree(true)[1..-1].each do |superclass| next if superclass.is_a?(YARD::CodeObjects::Proxy) next if !options.embed_mixins.empty? && options.embed_mixins_match?(superclass) != false attribs = superclass.attributes[:instance] attribs = attribs.select {|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 unless attribs.empty? end end def inherited_constant_list object.inheritance_tree(true)[1..-1].each do |superclass| next if superclass.is_a?(YARD::CodeObjects::Proxy) next if !options.embed_mixins.empty? && options.embed_mixins_match?(superclass) != false consts = superclass.constants(:included => false, :inherited => false) consts = consts.select {|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 unless consts.empty? end end def docstring_full(obj) docstring = obj.tags(:overload).size == 1 && obj.docstring.empty? ? obj.tag(:overload).docstring : obj.docstring if docstring.summary.empty? && obj.tags(:return).size == 1 && obj.tag(:return).text docstring = Docstring.new(obj.tag(:return).text.gsub(/\A([a-z])/, &:upcase).strip) end docstring end def docstring_summary(obj) docstring_full(obj).summary end def groups(list, type = "Method") groups_data = object.groups if groups_data 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.9.12/templates/default/onefile/0000755000004100000410000000000013206751010017630 5ustar www-datawww-datayard-0.9.12/templates/default/onefile/html/0000755000004100000410000000000013206751010020574 5ustar www-datawww-datayard-0.9.12/templates/default/onefile/html/headers.erb0000755000004100000410000000020013206751010022674 0ustar www-datawww-data yard-0.9.12/templates/default/onefile/html/readme.erb0000755000004100000410000000010713206751010022524 0ustar www-datawww-data
    <%= htmlify(parse_top_comments_from_file) %>
    yard-0.9.12/templates/default/onefile/html/files.erb0000755000004100000410000000015113206751010022370 0ustar www-datawww-data<% @files.each do |file| %> <% @file = file %>

    <%= file.title %>

    <%= diskfile %> <% end %>yard-0.9.12/templates/default/onefile/html/layout.erb0000755000004100000410000000103113206751010022601 0ustar www-datawww-data <%= defined?(@title) ? @title : '' %> <%= erb(:headers) %>

    <%= defined?(@title) ? @title : '' %>

    <%= yieldall %>
    <%= erb(:footer) %> yard-0.9.12/templates/default/onefile/html/setup.rb0000755000004100000410000000306613206751010022271 0ustar www-datawww-data# frozen_string_literal: true include 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 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) file = T('fulldoc').find_file(file) return unless 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 defined?(@readme) && @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 define_method(:serialize) do |object, data| return unless object == 'index.html' super(object, data) end define_method(:serialized_path) do |object| return object if object.is_a?(String) 'index.html' end end end yard-0.9.12/templates/default/constant/0000755000004100000410000000000013206751010020040 5ustar www-datawww-datayard-0.9.12/templates/default/constant/text/0000755000004100000410000000000013206751010021024 5ustar www-datawww-datayard-0.9.12/templates/default/constant/text/setup.rb0000755000004100000410000000012013206751010022505 0ustar www-datawww-data# frozen_string_literal: true def init sections :header, [T('docstring')] end yard-0.9.12/templates/default/constant/text/header.erb0000755000004100000410000000030113206751010022743 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.9.12/templates/default/class/0000755000004100000410000000000013206751010017314 5ustar www-datawww-datayard-0.9.12/templates/default/class/html/0000755000004100000410000000000013206751010020260 5ustar www-datawww-datayard-0.9.12/templates/default/class/html/constructor_details.erb0000755000004100000410000000047513206751010025055 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.9.12/templates/default/class/html/subclasses.erb0000755000004100000410000000024213206751010023122 0ustar www-datawww-data

    Direct Known Subclasses

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

    yard-0.9.12/templates/default/class/html/setup.rb0000755000004100000410000000007713206751010021754 0ustar www-datawww-data# frozen_string_literal: true include T('default/module/html') yard-0.9.12/templates/default/class/text/0000755000004100000410000000000013206751010020300 5ustar www-datawww-datayard-0.9.12/templates/default/class/text/subclasses.erb0000755000004100000410000000017213206751010023144 0ustar www-datawww-dataDirect Known Subclasses: ------------------------ <%= indent(wrap(@subclasses.map {|name, child| name }.join(", "))) %> yard-0.9.12/templates/default/class/text/setup.rb0000755000004100000410000000037713206751010021777 0ustar www-datawww-data# frozen_string_literal: true include 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}" end yard-0.9.12/templates/default/class/dot/0000755000004100000410000000000013206751010020102 5ustar www-datawww-datayard-0.9.12/templates/default/class/dot/superklass.erb0000755000004100000410000000024513206751010022774 0ustar www-datawww-data<% if object.superclass.path != "Object" && object.superclass.path != "BasicObject" %> <%= format_path object %> -> <%= format_path object.superclass %>; <% end %>yard-0.9.12/templates/default/class/dot/setup.rb0000755000004100000410000000016013206751010021567 0ustar www-datawww-data# frozen_string_literal: true include T('default/module/dot') def init super sections.push :superklass end yard-0.9.12/templates/default/class/setup.rb0000755000004100000410000000200013206751010020774 0ustar www-datawww-data# frozen_string_literal: true include 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) @ctor = ctors.find(&:constructor?) return unless @ctor 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(&:path).map do |child| name = child.path name = object.relative_path(child) if object.namespace [name, child] end erb(:subclasses) end yard-0.9.12/templates/default/layout/0000755000004100000410000000000013206751010017524 5ustar www-datawww-datayard-0.9.12/templates/default/layout/html/0000755000004100000410000000000013206751010020470 5ustar www-datawww-datayard-0.9.12/templates/default/layout/html/headers.erb0000755000004100000410000000106013206751010022575 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.9.12/templates/default/layout/html/search.erb0000755000004100000410000000073213206751010022434 0ustar www-datawww-datayard-0.9.12/templates/default/layout/html/index.erb0000755000004100000410000000010513206751010022270 0ustar www-datawww-data

    <%= options.title %>

    <%= yieldall %> yard-0.9.12/templates/default/layout/html/script_setup.erb0000755000004100000410000000025413206751010023712 0ustar www-datawww-data yard-0.9.12/templates/default/layout/html/objects.erb0000755000004100000410000000160113206751010022614 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.9.12/templates/default/layout/html/footer.erb0000755000004100000410000000033413206751010022463 0ustar www-datawww-data yard-0.9.12/templates/default/layout/html/files.erb0000755000004100000410000000045413206751010022272 0ustar www-datawww-data<% if @files && @files.size > 0 %>

    File Listing

    <% end %>
    yard-0.9.12/templates/default/layout/html/layout.erb0000755000004100000410000000072613206751010022507 0ustar www-datawww-data <%= erb(:headers) %>
    <%= yieldall %>
    <%= erb(:footer) %>
    yard-0.9.12/templates/default/layout/html/setup.rb0000755000004100000410000000450513206751010022164 0ustar www-datawww-data# frozen_string_literal: true def init @breadcrumb = [] @page_title = '' @breadcrumb_title = '' if @onefile sections :layout elsif defined?(@file) && @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 until 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 attr_reader :contents 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 layout @nav_url = url_for_list(!(defined?(@file) && @file) || options.index ? 'class' : 'file') @path = if !object || object.is_a?(String) nil elsif defined?(@file) && @file @file.path elsif !object.is_a?(YARD::CodeObjects::NamespaceObject) object.parent.path else object.path end erb(:layout) 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.9.12/templates/default/layout/html/listing.erb0000755000004100000410000000013313206751010022633 0ustar www-datawww-data

    Alphabetic Index

    <%= yieldall %>
    yard-0.9.12/templates/default/layout/html/breadcrumb.erb0000755000004100000410000000124513206751010023275 0ustar www-datawww-data yard-0.9.12/templates/default/layout/dot/0000755000004100000410000000000013206751010020312 5ustar www-datawww-datayard-0.9.12/templates/default/layout/dot/setup.rb0000755000004100000410000000036113206751010022002 0ustar www-datawww-data# frozen_string_literal: true attr_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.9.12/templates/default/layout/dot/header.erb0000755000004100000410000000024613206751010022241 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.9.12/templates/default/method/0000755000004100000410000000000013206751010017467 5ustar www-datawww-datayard-0.9.12/templates/default/method/html/0000755000004100000410000000000013206751010020433 5ustar www-datawww-datayard-0.9.12/templates/default/method/html/header.erb0000755000004100000410000000065013206751010022361 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.9.12/templates/default/method/text/0000755000004100000410000000000013206751010020453 5ustar www-datawww-datayard-0.9.12/templates/default/method/text/header.erb0000755000004100000410000000001713206751010022376 0ustar www-datawww-data<%= yieldall %>yard-0.9.12/templates/default/method/setup.rb0000755000004100000410000000012513206751010021155 0ustar www-datawww-data# frozen_string_literal: true def init sections :header, [T('method_details')] end yard-0.9.12/templates/default/fulldoc/0000755000004100000410000000000013206751010017637 5ustar www-datawww-datayard-0.9.12/templates/default/fulldoc/html/0000755000004100000410000000000013206751010020603 5ustar www-datawww-datayard-0.9.12/templates/default/fulldoc/html/full_list_file.erb0000755000004100000410000000041613206751010024275 0ustar www-datawww-data<% even_odd = 'odd' %> <% @items.each do |item| %>
  • <%= link_file item %>
  • <% even_odd = (even_odd == 'even' ? 'odd' : 'even') %> <% end %> yard-0.9.12/templates/default/fulldoc/html/js/0000755000004100000410000000000013206751010021217 5ustar www-datawww-datayard-0.9.12/templates/default/fulldoc/html/js/app.js0000755000004100000410000001643313206751010022347 0ustar www-datawww-data(function() { var localStorage = {}, sessionStorage = {}; try { localStorage = window.localStorage; } catch (e) { } try { sessionStorage = window.sessionStorage; } catch (e) { } function 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().css('display', 'inline'); $(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 searchFrameButtons() { $('.full_list_link').click(function() { toggleSearchFrame(this, $(this).attr('href')); return false; }); window.addEventListener('message', function(e) { if (e.data === 'navEscape') { $('#nav').slideUp(100); $('#search a').removeClass('active inactive'); $(window).focus(); } }); $(window).resize(function() { if ($('#search:visible').length === 0) { $('#nav').removeAttr('style'); $('#search a').removeClass('active inactive'); $(window).focus(); } }); } function toggleSearchFrame(id, link) { var frame = $('#nav'); $('#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'); if (frame.attr('src') !== link) frame.attr('src', link); frame.slideDown(100); } } function linkSummaries() { $('.summary_signature').click(function() { document.location = $(this).find('a').attr('href'); }); } function summaryToggle() { $('.summary_toggle').click(function(e) { e.preventDefault(); 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.summaryCollapsed == "collapse") { $('.summary_toggle').first().click(); } else { localStorage.summaryCollapsed = "expand"; } } 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(); }); } function navResizeFn(e) { if (e.which !== 1) { navResizeFnStop(); return; } sessionStorage.navWidth = e.pageX.toString(); $('.nav_wrap').css('width', e.pageX); $('.nav_wrap').css('-ms-flex', 'inherit'); } function navResizeFnStop() { $(window).unbind('mousemove', navResizeFn); window.removeEventListener('message', navMessageFn, false); } function navMessageFn(e) { if (e.data.action === 'mousemove') navResizeFn(e.data.event); if (e.data.action === 'mouseup') navResizeFnStop(); } function navResizer() { $('#resizer').mousedown(function(e) { e.preventDefault(); $(window).mousemove(navResizeFn); window.addEventListener('message', navMessageFn, false); }); $(window).mouseup(navResizeFnStop); if (sessionStorage.navWidth) { navResizeFn({which: 1, pageX: parseInt(sessionStorage.navWidth, 10)}); } } function navExpander() { var done = false, timer = setTimeout(postMessage, 500); function postMessage() { if (done) return; clearTimeout(timer); var opts = { action: 'expand', path: pathId }; document.getElementById('nav').contentWindow.postMessage(opts, '*'); done = true; } window.addEventListener('message', function(event) { if (event.data === 'navReady') postMessage(); return false; }, false); } function mainFocus() { var hash = window.location.hash; if (hash !== '' && $(hash)[0]) { $(hash)[0].scrollIntoView(); } setTimeout(function() { $('#main').focus(); }, 10); } $(document).ready(function() { navResizer(); navExpander(); createSourceLinks(); createDefineLinks(); createFullTreeLinks(); searchFrameButtons(); linkSummaries(); summaryToggle(); generateTOC(); mainFocus(); }); })(); yard-0.9.12/templates/default/fulldoc/html/js/full_list.js0000755000004100000410000001316213206751010023560 0ustar www-datawww-data(function() { var $clicked = $(null); var searchTimeout = null; var searchCache = []; var caseSensitiveMatch = false; var ignoreKeyCodeMin = 8; var ignoreKeyCodeMax = 46; var commandKey = 91; RegExp.escape = function(text) { return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); } function escapeShortcut() { $(document).keydown(function(evt) { if (evt.which == 27) { window.parent.postMessage('navEscape', '*'); } }); } function navResizer() { $(window).mousemove(function(e) { window.parent.postMessage({ action: 'mousemove', event: {pageX: e.pageX, which: e.which} }, '*'); }).mouseup(function(e) { window.parent.postMessage({action: 'mouseup'}, '*'); }); window.parent.postMessage("navReady", "*"); } function clearSearchTimeout() { clearTimeout(searchTimeout); searchTimeout = null; } function enableLinks() { // load the target page in the parent window $('#full_list li').on('click', function(evt) { $('#full_list li').removeClass('clicked'); $clicked = $(this); $clicked.addClass('clicked'); evt.stopPropagation(); if (evt.target.tagName === 'A') return true; var elem = $clicked.find('> .item .object_link a')[0]; var e = evt.originalEvent; var newEvent = new MouseEvent(evt.originalEvent.type); newEvent.initMouseEvent(e.type, e.canBubble, e.cancelable, e.view, e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget); elem.dispatchEvent(newEvent); evt.preventDefault(); return false; }); } function enableToggles() { // show/hide nested classes on toggle click $('#full_list a.toggle').on('click', function(evt) { evt.stopPropagation(); evt.preventDefault(); $(this).parent().parent().toggleClass('collapsed'); highlight(); }); } function populateSearchCache() { $('#full_list li .item').each(function() { var $node = $(this); var $link = $node.find('.object_link a'); if ($link.length > 0) { searchCache.push({ node: $node, link: $link, name: $link.text(), fullName: $link.attr('title').split(' ')[0] }); } }); } function enableSearch() { $('#search input').keyup(function(event) { if (ignoredKeyPress(event)) return; if (this.value === "") { clearSearch(); } else { performSearch(this.value); } }); $('#full_list').after(""); } function ignoredKeyPress(event) { if ( (event.keyCode > ignoreKeyCodeMin && event.keyCode < ignoreKeyCodeMax) || (event.keyCode == commandKey) ) { return true; } else { return false; } } function clearSearch() { clearSearchTimeout(); $('#full_list .found').removeClass('found').each(function() { var $link = $(this).find('.object_link a'); $link.text($link.text()); }); $('#full_list, #content').removeClass('insearch'); $clicked.parents().removeClass('collapsed'); highlight(); } function performSearch(searchString) { clearSearchTimeout(); $('#full_list, #content').addClass('insearch'); $('#noresults').text('').hide(); partialSearch(searchString, 0); } function partialSearch(searchString, offset) { var lastRowClass = ''; var i = null; for (i = offset; i < Math.min(offset + 50, searchCache.length); i++) { var item = searchCache[i]; var searchName = (searchString.indexOf('::') != -1 ? item.fullName : item.name); var matchString = buildMatchString(searchString); var matchRegexp = new RegExp(matchString, caseSensitiveMatch ? "" : "i"); if (searchName.match(matchRegexp) == null) { item.node.removeClass('found'); item.link.text(item.link.text()); } else { item.node.addClass('found'); item.node.removeClass(lastRowClass).addClass(lastRowClass == 'r1' ? 'r2' : 'r1'); lastRowClass = item.node.hasClass('r1') ? 'r1' : 'r2'; item.link.html(item.name.replace(matchRegexp, "$&")); } } if(i == searchCache.length) { searchDone(); } else { searchTimeout = setTimeout(function() { partialSearch(searchString, i); }, 0); } } function searchDone() { searchTimeout = null; highlight(); if ($('#full_list li:visible').size() === 0) { $('#noresults').text('No results were found.').hide().fadeIn(); } else { $('#noresults').text('').hide(); } $('#content').removeClass('insearch'); } function buildMatchString(searchString, event) { caseSensitiveMatch = searchString.match(/[A-Z]/) != null; var regexSearchString = RegExp.escape(searchString); if (caseSensitiveMatch) { regexSearchString += "|" + $.map(searchString.split(''), function(e) { return RegExp.escape(e); }). join('.+?'); } return regexSearchString; } function highlight() { $('#full_list li:visible').each(function(n) { $(this).removeClass('even odd').addClass(n % 2 == 0 ? 'odd' : 'even'); }); } /** * Expands the tree to the target element and its immediate * children. */ function expandTo(path) { var $target = $(document.getElementById('object_' + path)); $target.addClass('clicked'); $target.removeClass('collapsed'); $target.parentsUntil('#full_list', 'li').removeClass('collapsed'); if($target[0]) { window.scrollTo(window.scrollX, $target.offset().top - 250); highlight(); } } function windowEvents(event) { var msg = event.data; if (msg.action === "expand") { expandTo(msg.path); } return false; } window.addEventListener("message", windowEvents, false); $(document).ready(function() { escapeShortcut(); navResizer(); enableLinks(); enableToggles(); populateSearchCache(); enableSearch(); }); })(); yard-0.9.12/templates/default/fulldoc/html/js/jquery.js0000755000004100000410000026725413206751010023117 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.9.12/templates/default/fulldoc/html/frames.erb0000755000004100000410000000071713206751010022562 0ustar www-datawww-data <%= options.title %> yard-0.9.12/templates/default/fulldoc/html/css/0000755000004100000410000000000013206751010021373 5ustar www-datawww-datayard-0.9.12/templates/default/fulldoc/html/css/full_list.css0000755000004100000410000001300413206751010024103 0ustar www-datawww-databody { margin: 0; font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; font-size: 13px; height: 101%; overflow-x: hidden; background: #fafafa; } h1 { padding: 12px 10px; padding-bottom: 0; margin: 0; font-size: 1.4em; } .clear { clear: both; } .fixed_header { position: fixed; background: #fff; width: 100%; padding-bottom: 10px; margin-top: 0; top: 0; z-index: 9999; height: 70px; } #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; margin-top: 80px; font-size: 1.1em; } #full_list ul { padding: 0; } #full_list li { padding: 0; margin: 0; list-style: none; } #full_list li .item { padding: 5px 5px 5px 12px; } #noresults { padding: 7px 12px; background: #fff; } #content.insearch #noresults { margin-left: 7px; } li.collapsed ul { display: none; } 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.odd { background: #f0f0f0; } li.even { background: #fafafa; } .item:hover { background: #ddd; } li small:before { content: "("; } li small:after { content: ")"; } li small.search_info { display: none; } a, a:visited { text-decoration: none; color: #05a; } li.clicked > .item { background: #05a; color: #ccc; } li.clicked > .item a, li.clicked > .item a:visited { color: #eee; } li.clicked > .item a.toggle { opacity: 0.5; background-position: bottom right; } li.collapsed.clicked a.toggle { background-position: top right; } #search input { border: 1px solid #bbb; border-radius: 3px; } #full_list_nav { margin-left: 10px; font-size: 0.9em; display: block; color: #aaa; } #full_list_nav a, #nav a:visited { color: #358; } #full_list_nav a:hover { background: transparent; color: #5af; } #full_list_nav span:after { content: ' | '; } #full_list_nav span:last-child:after { content: ''; } #content h1 { margin-top: 0; } li { white-space: nowrap; cursor: normal; } li small { display: block; font-size: 0.8em; } li small:before { content: ""; } li small:after { content: ""; } li small.search_info { display: none; } #search { width: 170px; position: static; margin: 3px; margin-left: 10px; font-size: 0.9em; color: #888; padding-left: 0; padding-right: 24px; } #content.insearch #search { background-position: center right; } #search input { width: 110px; } #full_list.insearch ul { display: block; } #full_list.insearch .item { display: none; } #full_list.insearch .found { display: block; padding-left: 11px !important; } #full_list.insearch li a.toggle { display: none; } #full_list.insearch li small.search_info { display: block; } yard-0.9.12/templates/default/fulldoc/html/css/common.css0000755000004100000410000000005213206751010023375 0ustar www-datawww-data/* Override this file with custom rules */yard-0.9.12/templates/default/fulldoc/html/css/style.css0000755000004100000410000005032513206751010023255 0ustar www-datawww-datahtml { width: 100%; height: 100%; } body { font-family: "Lucida Sans", "Lucida Grande", Verdana, Arial, sans-serif; font-size: 13px; width: 100%; margin: 0; padding: 0; display: flex; display: -webkit-flex; display: -ms-flexbox; } #nav { position: relative; width: 100%; height: 100%; border: 0; border-right: 1px dotted #eee; overflow: auto; } .nav_wrap { margin: 0; padding: 0; width: 20%; height: 100%; position: relative; display: flex; display: -webkit-flex; display: -ms-flexbox; flex-shrink: 0; -webkit-flex-shrink: 0; -ms-flex: 1 0; } #resizer { position: absolute; right: -5px; top: 0; width: 10px; height: 100%; cursor: col-resize; z-index: 9999; } #main { flex: 5 1; -webkit-flex: 5 1; -ms-flex: 5 1; outline: none; position: relative; background: #fff; padding: 1.2em; padding-top: 0.2em; } @media (max-width: 920px) { .nav_wrap { width: 100%; top: 0; right: 0; overflow: visible; position: absolute; } #resizer { display: none; } #nav { z-index: 9999; background: #fff; display: none; position: absolute; top: 40px; right: 12px; width: 500px; max-width: 80%; height: 80%; overflow-y: scroll; border: 1px solid #999; border-collapse: collapse; box-shadow: -7px 5px 25px #aaa; border-radius: 2px; } } @media (min-width: 920px) { body { height: 100%; overflow: hidden; } #main { height: 100%; overflow: auto; } #search { display: none; } } #main img { max-width: 100%; } 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; position: relative; } h2 small { font-weight: normal; font-size: 0.7em; display: inline; position: absolute; right: 0; } h2 small a { display: block; height: 20px; border: 1px solid #aaa; border-bottom: 0; border-top-left-radius: 5px; background: #f8f8f8; position: relative; padding: 2px 7px; } .clear { clear: both; } .inline { display: inline; } .inline p:first-child { display: inline; } .docstring, .tags, #filecontents { font-size: 15px; line-height: 1.5145em; } .docstring p > code, .docstring p > tt, .tags p > code, .tags p > tt { color: #c7254e; background: #f9f2f4; padding: 2px 4px; font-size: 1em; border-radius: 4px; } .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 a, .docstring .object_link a { font-family: monospace; font-size: 1.05em; color: #05a; background: #EDF4FA; padding: 2px 4px; font-size: 1em; border-radius: 4px; } .rdoc-term { padding-right: 25px; font-weight: bold; } .rdoc-list p { margin: 0; padding: 0; margin-bottom: 4px; } .summary_desc pre.code .object_link a, .docstring pre.code .object_link a { padding: 0px; background: inherit; color: inherit; border-radius: inherit; } /* 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; margin: 20px 0; padding: 10px; border: 1px solid #eee; border-radius: 3px; display: block; } .docstring .note { border-left-color: #ccc; border-left-width: 5px; } .note.todo { background: #ffffc5; border-color: #ececaa; } .note.returns_void { background: #efefef; } .note.deprecated { background: #ffe5e5; border-color: #e9dada; } .note.title.deprecated { background: #ffe5e5; border-color: #e9dada; } .note.private { background: #ffffc5; border-color: #ececaa; } .note.title { padding: 3px 6px; 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 { background: #efefef; } .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; } .box_info dl { margin: 0; border: 0; width: 100%; font-size: 1em; display: flex; display: -webkit-flex; display: -ms-flexbox; } .box_info dl dt { flex-shrink: 0; -webkit-flex-shrink: 1; -ms-flex-shrink: 1; width: 100px; text-align: right; font-weight: bold; border: 1px solid #aaa; border-width: 1px 0px 0px 1px; padding: 6px 0; padding-right: 10px; } .box_info dl dd { flex-grow: 1; -webkit-flex-grow: 1; -ms-flex: 1; max-width: 420px; padding: 6px 0; padding-right: 20px; border: 1px solid #aaa; border-width: 1px 1px 0 0; overflow: hidden; position: relative; } .box_info dl:last-child > * { border-bottom: 1px solid #aaa; } .box_info dl:nth-child(odd) > * { background: #eee; } .box_info dl:nth-child(even) > * { background: #fff; } .box_info dl > * { margin: 0; } 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-block; padding: 0 12px; line-height: 30px; margin-bottom: 5px; } dl.constants { margin-left: 10px; } 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; } dl.constants .docstring .note:first-child { margin-top: 5px; } .summary_desc { margin-left: 32px; display: block; font-family: sans-serif; font-size: 1.1em; margin-top: 8px; line-height: 1.5145em; margin-bottom: 0.8em; } .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 #ccc; margin-top: 25px; padding-top: 0; } .method_details.first { border: 0; margin-top: 5px; } .method_details.first h3.signature { margin-top: 1em; } p.signature, h3.signature { font-size: 1.1em; font-weight: normal; font-family: Monaco, Consolas, Courier, monospace; padding: 6px 10px; margin-top: 1em; background: #E8F4FF; border: 1px solid #d8d8e5; border-radius: 5px; } 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: 1.05em; margin-bottom: 0; font-weight: bold; } .tags .tag_title tt { color: initial; padding: initial; background: initial; } .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; font-weight: bold; font-size: 1em; } .tags .examples .inline p:before { content: "â–¸"; font-size: 1em; margin-right: 5px; } .tags .overload .overload_item { list-style: none; margin-bottom: 25px; } .tags .overload .overload_item .signature { padding: 2px 8px; background: #F1F8FF; border: 1px solid #d8d8e5; 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, .showSource a:visited { text-decoration: none; color: #666; } #content a, #content a:visited { text-decoration: none; color: #05a; } #content a:hover { background: #ffffa5; } ul.summary { list-style: none; font-family: monospace; font-size: 1em; line-height: 1.5em; padding-left: 0px; } ul.summary a, ul.summary a:visited { text-decoration: none; font-size: 1.1em; } ul.summary li { margin-bottom: 5px; } .summary .summary_signature { padding: 4px 8px; background: #f8f8f8; border: 1px solid #f0f0f0; border-radius: 5px; } .summary_signature:hover { background: #CFEBFF; border-color: #A4CCDA; 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, #content .summary_signature:hover a:visited { background: transparent; color: #049; } 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: 12px; top: 0px; z-index: 9000; } #search a { display: block; float: left; padding: 4px 8px; text-decoration: none; color: #05a; fill: #05a; border: 1px solid #d8d8e5; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; background: #F1F8FF; box-shadow: -1px 1px 3px #ddd; } #search a:hover { background: #f5faff; color: #06b; fill: #06b; } #search a.active { background: #568; padding-bottom: 20px; color: #fff; fill: #fff; border: 1px solid #457; border-top-left-radius: 5px; border-top-right-radius: 5px; } #search a.inactive { color: #999; fill: #999; } .inheritanceTree, .toggleDefines { float: right; border-left: 1px solid #aaa; position: absolute; top: 0; right: 0; height: 100%; background: #f6f6f6; padding: 5px; min-width: 55px; text-align: center; } #menu { font-size: 1.3em; color: #bbb; } #menu .title, #menu a { font-size: 0.7em; } #menu .title a { font-size: 1em; } #menu .title { color: #555; } #menu a, #menu a:visited { color: #333; text-decoration: none; border-bottom: 1px dotted #bbd; } #menu a:hover { color: #05a; } #footer { margin-top: 15px; border-top: 1px solid #ccc; text-align: center; padding: 7px 0; color: #999; } #footer a, #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; } #content ul.summary li.deprecated .summary_signature a, #content ul.summary li.deprecated .summary_signature a:visited { text-decoration: line-through; font-style: italic; } #toc { position: relative; float: right; overflow-x: auto; right: -3px; margin-left: 20px; margin-bottom: 20px; padding: 20px; padding-right: 30px; max-width: 300px; z-index: 5000; background: #fefefe; border: 1px solid #ddd; box-shadow: -2px 2px 6px #bbb; } #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: #fefefe; box-shadow: none; } #toc.hidden:hover { background: #fafafa; } #filecontents h1 + #toc.nofloat { margin-top: 0; } @media (max-width: 560px) { #toc { margin-left: 0; margin-top: 16px; float: none; max-width: none; } } /* 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: 9px 14px; margin-top: 4px; border: 1px solid #e1e1e8; background: #f7f7f9; border-radius: 4px; font-size: 1em; overflow-x: auto; line-height: 1.2em; } pre.code { color: #000; tab-size: 2; } 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 .qwords_sep, pre.code .words_beg, pre.code .words_end, pre.code .words_sep, pre.code .qsymbols_beg, pre.code .qsymbols_end, pre.code .qsymbols_sep, pre.code .symbols_beg, pre.code .symbols_end, pre.code .symbols_sep, 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; } /* inline code */ p > code { padding: 1px 3px 1px 3px; border: 1px solid #E1E1E8; background: #F7F7F9; border-radius: 4px; } /* Color fix for links */ #content .summary_desc pre.code .id > .object_link a, /* identifier */ #content .docstring pre.code .id > .object_link a { color: #0085FF; } #content .summary_desc pre.code .const > .object_link a, /* constant */ #content .docstring pre.code .const > .object_link a { color: #585CF6; } yard-0.9.12/templates/default/fulldoc/html/full_list_class.erb0000755000004100000410000000025113206751010024460 0ustar www-datawww-data
          • <%= link_object(Registry.root, Registry.root.title, nil, false) %>
          • <%= class_list %> yard-0.9.12/templates/default/fulldoc/html/full_list.erb0000755000004100000410000000224113206751010023274 0ustar www-datawww-data <% stylesheets_full_list.each do |stylesheet| %> <% end %> <% javascripts_full_list.each do |javascript| %> <% end %> <%= @list_title %>

            <%= @list_title %>

            <% menu_lists.each do |list| %> <%= list[:title] %> <% end %>
              <%= erb "full_list_#{@list_type}" %>
            yard-0.9.12/templates/default/fulldoc/html/full_list_method.erb0000755000004100000410000000052513206751010024637 0ustar www-datawww-data<% even_odd = 'odd' %> <% @items.each do |item| %>
          • <%= linkify item, h(item.name(true)) %> <%= item.namespace.title %>
          • <% even_odd = (even_odd == 'even' ? 'odd' : 'even') %> <% end %> yard-0.9.12/templates/default/fulldoc/html/setup.rb0000755000004100000410000001552213206751010022300 0ustar www-datawww-data# frozen_string_literal: true include 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.readme.nil? 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.merge(:index => true)) 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) # rubocop:disable Lint/UnusedMethodArgument 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 documentation 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 # @api private class TreeContext def initialize @depth = 0 @even_odd = Alternator.new(:even, :odd) end def nest @depth += 1 yield @depth -= 1 end # @return [String] Returns a css pixel offset, e.g. "30px" def indent "#{(@depth + 2) * 15}px" end def classes classes = [] classes << 'collapsed' if @depth > 0 classes << @even_odd.next if @depth < 2 classes end class Alternator def initialize(first, second) @next = first @after = second end def next @next, @after = @after, @next @after end end end # @return [String] HTML output of the classes to be displayed in the # full_list_class template. def class_list(root = Registry.root, tree = TreeContext.new) out = String.new("") children = run_verifier(root.children) if root == Registry.root children += @items.select {|o| o.namespace.is_a?(CodeObjects::Proxy) } end children.compact.sort_by(&:path).each do |child| next unless 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 << "
            " 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 << "
            " tree.nest do out << "
              #{class_list(child, tree)}
            " if has_children end out << "
          • " end out end yard-0.9.12/templates/guide/0000755000004100000410000000000013206751010015660 5ustar www-datawww-datayard-0.9.12/templates/guide/tags/0000755000004100000410000000000013206751010016616 5ustar www-datawww-datayard-0.9.12/templates/guide/tags/html/0000755000004100000410000000000013206751010017562 5ustar www-datawww-datayard-0.9.12/templates/guide/tags/html/setup.rb0000755000004100000410000000025213206751010021251 0ustar www-datawww-data# frozen_string_literal: true include T('default/tags/html') def init super [:since, :see, :return].each do |section| sections[:index].delete(section) end end yard-0.9.12/templates/guide/docstring/0000755000004100000410000000000013206751010017654 5ustar www-datawww-datayard-0.9.12/templates/guide/docstring/html/0000755000004100000410000000000013206751010020620 5ustar www-datawww-datayard-0.9.12/templates/guide/docstring/html/setup.rb0000755000004100000410000000010213206751010022301 0ustar www-datawww-data# frozen_string_literal: true include T('default/docstring/html') yard-0.9.12/templates/guide/module/0000755000004100000410000000000013206751010017145 5ustar www-datawww-datayard-0.9.12/templates/guide/module/html/0000755000004100000410000000000013206751010020111 5ustar www-datawww-datayard-0.9.12/templates/guide/module/html/method_list.erb0000755000004100000410000000024113206751010023116 0ustar www-datawww-data
            <% @meths.each_with_index do |meth, i| %> <%= yieldall(:object => meth, :index => i, :in_module => true) %> <% end %>
            yard-0.9.12/templates/guide/module/html/setup.rb0000755000004100000410000000135013206751010021600 0ustar www-datawww-data# frozen_string_literal: true include 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(&: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.9.12/templates/guide/module/html/header.erb0000755000004100000410000000055313206751010022041 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.9.12/templates/guide/onefile/0000755000004100000410000000000013206751010017301 5ustar www-datawww-datayard-0.9.12/templates/guide/onefile/html/0000755000004100000410000000000013206751010020245 5ustar www-datawww-datayard-0.9.12/templates/guide/onefile/html/toc.erb0000755000004100000410000000013013206751010021521 0ustar www-datawww-data

            <%= @title %>

            Table of Contents

            yard-0.9.12/templates/guide/onefile/html/files.erb0000755000004100000410000000011513206751010022041 0ustar www-datawww-data<% @files.each do |file| %> <% @file = file %> <%= diskfile %> <% end %> yard-0.9.12/templates/guide/onefile/html/setup.rb0000755000004100000410000000016113206751010021733 0ustar www-datawww-data# frozen_string_literal: true include T('default/onefile/html') def init sections :layout, [:toc, :files] end yard-0.9.12/templates/guide/class/0000755000004100000410000000000013206751010016765 5ustar www-datawww-datayard-0.9.12/templates/guide/class/html/0000755000004100000410000000000013206751010017731 5ustar www-datawww-datayard-0.9.12/templates/guide/class/html/setup.rb0000755000004100000410000000007513206751010021423 0ustar www-datawww-data# frozen_string_literal: true include T('guide/module/html') yard-0.9.12/templates/guide/layout/0000755000004100000410000000000013206751010017175 5ustar www-datawww-datayard-0.9.12/templates/guide/layout/html/0000755000004100000410000000000013206751010020141 5ustar www-datawww-datayard-0.9.12/templates/guide/layout/html/layout.erb0000755000004100000410000000415413206751010022157 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.9.12/templates/guide/layout/html/setup.rb0000755000004100000410000000105513206751010021632 0ustar www-datawww-data# frozen_string_literal: true include T('default/layout/html') def init super @topfile = options.readme if options.files if @topfile @toptitle = @topfile.attributes[:title] || "Documentation Overview" end @page_title = @file == options.readme ? options.title : @file.title 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.9.12/templates/guide/method/0000755000004100000410000000000013206751010017140 5ustar www-datawww-datayard-0.9.12/templates/guide/method/html/0000755000004100000410000000000013206751010020104 5ustar www-datawww-datayard-0.9.12/templates/guide/method/html/setup.rb0000755000004100000410000000102413206751010021571 0ustar www-datawww-data# frozen_string_literal: true def 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 if params.empty? "" else args = params.map {|n, v| v ? "#{h n} = #{h v}" : "" + n.to_s + "" }.join(", ") args end end yard-0.9.12/templates/guide/method/html/header.erb0000755000004100000410000000243313206751010022033 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.9.12/templates/guide/fulldoc/0000755000004100000410000000000013206751010017310 5ustar www-datawww-datayard-0.9.12/templates/guide/fulldoc/html/0000755000004100000410000000000013206751010020254 5ustar www-datawww-datayard-0.9.12/templates/guide/fulldoc/html/js/0000755000004100000410000000000013206751010020670 5ustar www-datawww-datayard-0.9.12/templates/guide/fulldoc/html/js/app.js0000755000004100000410000000211613206751010022011 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.9.12/templates/guide/fulldoc/html/css/0000755000004100000410000000000013206751010021044 5ustar www-datawww-datayard-0.9.12/templates/guide/fulldoc/html/css/style.css0000755000004100000410000001223113206751010022720 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.9.12/templates/guide/fulldoc/html/setup.rb0000755000004100000410000000354613206751010021754 0ustar www-datawww-data# frozen_string_literal: true include 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 define_method(:serialized_path) do |object| if CodeObjects::ExtraFileObject === object super(object).sub(/^file\./, '').downcase else super(object) 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) if 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.9.12/spec/0000755000004100000410000000000013206751010013517 5ustar www-datawww-datayard-0.9.12/spec/server_spec.rb0000755000004100000410000000113213206751010016364 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::Server do describe ".register_static_path" do it "registers a static path" do YARD::Server.register_static_path 'foo' expect(YARD::Server::Commands::StaticFileCommand::STATIC_PATHS.last).to eq "foo" end it "does not duplicate paths" do paths = YARD::Server::Commands::StaticFileCommand::STATIC_PATHS count = paths.size YARD::Server.register_static_path 'foo2' YARD::Server.register_static_path 'foo2' expect(paths.size).to eq(count + 1) expect(paths.last).to eq 'foo2' end end end yard-0.9.12/spec/tags/0000755000004100000410000000000013206751010014455 5ustar www-datawww-datayard-0.9.12/spec/tags/default_factory_spec.rb0000755000004100000410000001365213206751010021201 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::Tags::DefaultFactory do before { @f = YARD::Tags::DefaultFactory.new } describe "#parse_tag" do it "does not have trailing whitespace on a regular freeform tag" do expect(@f.parse_tag('api', 'private ').text).to eq "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 "handles one type" do expect(parse_types('[A]')).to eq [nil, ['A'], ""] end it "handles a list of types" do expect(parse_types('[A, B, C]')).to eq [nil, ['A', 'B', 'C'], ""] end it "handles ducktypes" do expect(parse_types('[#foo]')).to eq [nil, ['#foo'], ''] end %w(#foo= #<< #<=> #>> #== #=== Array<#<=>> Array<#==>).each do |meth| it "handles ducktypes with special method name #{meth}" do expect(parse_types("[#{meth}]")).to eq [nil, [meth], ''] end end it "only parses #ducktypes inside brackets" do expect(parse_types("#ducktype")).to eq [nil, nil, '#ducktype'] end it "returns the text before and after the type list" do expect(parse_types(' b description')).to eq ['b', ['String'], 'description'] expect(parse_types('b c description (test)')).to eq [nil, nil, 'b c description (test)'] end it "does not allow types to start after a newline" do v = parse_types(" \n [X]") expect(v).to eq [nil, nil, "[X]"] end it "handles a complex list of types" do v = parse_types(' [Test, Array, String]') expect(v).to include(["Test", "Array", "String"]) end it "handles 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}') expect(a).to eq b expect(b).to eq c expect(c).to eq d expect(a).to include(['a', 'b', 'c']) end it "returns the text before the type list as the last element" do expect(parse_types('b[x, y, z]')).to eq ['b', ['x', 'y', 'z'], ''] expect(parse_types(' ! ')).to eq ["!", ['x'], ''] end it "returns text unparsed if there is no type list" do expect(parse_types('')).to eq [nil, nil, ''] expect(parse_types('[]')).to eq [nil, nil, '[]'] end it "allows A => B syntax" do v = parse_types(' [Test, Array {B => C}}, C>, String]') expect(v).to include(["Test", "Array {B => C}}, C>", "String"]) end it "handles quoted values" do v = parse_types(' ["foo, bar", \'baz, qux\', in"them,iddle"]') expect(v).to include(["\"foo, bar\"", "'baz, qux'", 'in"them,iddle"']) end end describe "#parse_tag_with_types" do def parse_types(text) @f.send(:parse_tag_with_types, 'test', text) end it "parses given types and description" do expect(YARD::Tags::Tag).to receive(:new).with("test", "description", ["x", "y", "z"]) parse_types(' [x, y, z] description') end it "parses given types only" do expect(YARD::Tags::Tag).to receive(:new).with("test", "", ["x", "y", "z"]) parse_types(' [x, y, z] ') end it "allows type list to be omitted" do expect(YARD::Tags::Tag).to receive(:new).with('test', 'description', nil) parse_types(' description ') end it "raises an error if a name is specified before type list" do expect { parse_types('b desc') }.to 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 "parses a standard type list with name before types (no default)" do expect(YARD::Tags::DefaultTag).to receive(:new).with("test", "description", ["x", "y", "z"], 'NAME', nil) parse_types('NAME [x, y, z] description') end it "parses a standard type list with name after types (no default)" do expect(YARD::Tags::DefaultTag).to receive(:new).with("test", "description", ["x", "y", "z"], 'NAME', nil) parse_types(' [x, y, z] NAME description') end it "parses a tag definition with name, typelist and default" do expect(YARD::Tags::DefaultTag).to receive(:new).with("test", "description", ["x", "y", "z"], 'NAME', ['default', 'values']) parse_types(' [x, y, z] NAME (default, values) description') end it "parses a tag definition with name, typelist and default when name is before type list" do expect(YARD::Tags::DefaultTag).to receive(:new).with("test", "description", ["x", "y", "z"], 'NAME', ['default', 'values']) parse_types(' NAME [x, y, z] (default, values) description') end it "allows typelist to be omitted" do expect(YARD::Tags::DefaultTag).to 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 "has a name before tag info" do t = parse_options("xyz key [Types] (default) description") expect(t.tag_name).to eq 'option' expect(t.name).to eq 'xyz' end it "parses the rest of the tag like DefaultTag" do t = parse_options("xyz key [Types] (default) description") expect(t.pair).to be_instance_of(Tags::DefaultTag) expect(t.pair.types).to eq ["Types"] expect(t.pair.name).to eq "key" expect(t.pair.defaults).to eq ["default"] expect(t.pair.text).to eq "description" end it "allows omitting default" do t = parse_options("xyz [Types] key") expect(t.pair).to be_instance_of(Tags::DefaultTag) expect(t.pair.name).to eq "key" end end end yard-0.9.12/spec/tags/types_explainer_spec.rb0000755000004100000410000001546013206751010021240 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::Tags::TypesExplainer do Type = YARD::Tags::TypesExplainer::Type CollectionType = YARD::Tags::TypesExplainer::CollectionType FixedCollectionType = YARD::Tags::TypesExplainer::FixedCollectionType HashCollectionType = YARD::Tags::TypesExplainer::HashCollectionType Parser = YARD::Tags::TypesExplainer::Parser def parse(types) Parser.new(types).parse end def parse_fail(types) expect(lambda { parse(types) }).to raise_error(SyntaxError) end describe Type, '#to_s' do before { @t = Type.new(nil) } it "works for a class/module reference" do @t.name = "ClassModuleName" expect(@t.to_s).to eq "a ClassModuleName" expect(@t.to_s(false)).to eq "ClassModuleNames" @t.name = "XYZ" expect(@t.to_s).to eq "a XYZ" expect(@t.to_s(false)).to eq "XYZ's" @t.name = "Array" expect(@t.to_s).to eq "an Array" expect(@t.to_s(false)).to eq "Arrays" end it "works for a method (ducktype)" do @t.name = "#mymethod" expect(@t.to_s).to eq "an object that responds to #mymethod" expect(@t.to_s(false)).to eq "objects that respond to #mymethod" end it "works for a constant value" do ['false', 'true', 'nil', '4'].each do |name| @t.name = name expect(@t.to_s).to eq name expect(@t.to_s(false)).to eq name end end end describe CollectionType, '#to_s' do before { @t = CollectionType.new("Array", nil) } it "can contain one item" do @t.types = [Type.new("Object")] expect(@t.to_s).to eq "an Array of (Objects)" end it "can contain more than one item" do @t.types = [Type.new("Object"), Type.new("String"), Type.new("Symbol")] expect(@t.to_s).to eq "an Array of (Objects, Strings or Symbols)" end it "can contain nested collections" do @t.types = [CollectionType.new("List", [Type.new("Object")])] expect(@t.to_s).to eq "an Array of (a List of (Objects))" end end describe FixedCollectionType, '#to_s' do before { @t = FixedCollectionType.new("Array", nil) } it "can contain one item" do @t.types = [Type.new("Object")] expect(@t.to_s).to eq "an Array containing (an Object)" end it "can contain more than one item" do @t.types = [Type.new("Object"), Type.new("String"), Type.new("Symbol")] expect(@t.to_s).to eq "an Array containing (an Object followed by a String followed by a Symbol)" end it "can contain nested collections" do @t.types = [FixedCollectionType.new("List", [Type.new("Object")])] expect(@t.to_s).to eq "an Array containing (a List containing (an Object))" end end describe FixedCollectionType, '#to_s' do before { @t = HashCollectionType.new("Hash", nil, nil) } it "can contain a single key type and value type" do @t.key_types = [Type.new("Object")] @t.value_types = [Type.new("Object")] expect(@t.to_s).to eq "a Hash with keys made of (Objects) and values of (Objects)" end it "can contain multiple key types" do @t.key_types = [Type.new("Key"), Type.new("String")] @t.value_types = [Type.new("Object")] expect(@t.to_s).to eq "a Hash with keys made of (Keys or Strings) and values of (Objects)" end it "can contain multiple value types" do @t.key_types = [Type.new("String")] @t.value_types = [Type.new("true"), Type.new("false")] expect(@t.to_s).to eq "a Hash with keys made of (Strings) and values of (true or false)" end end describe Parser, '#parse' do it "parses a regular class name" do type = parse("MyClass") expect(type.size).to eq 1 expect(type.first).to be_a(Type) expect(type.first.name).to eq "MyClass" end it "parses a path reference name" do type = parse("A::B") expect(type.size).to eq 1 expect(type.first).to be_a(Type) expect(type.first.name).to eq "A::B" end it "parses a list of simple names" do type = parse("A, B::C, D, E") expect(type.size).to eq 4 expect(type[0].name).to eq "A" expect(type[1].name).to eq "B::C" expect(type[2].name).to eq "D" expect(type[3].name).to eq "E" end it "parses a collection type" do type = parse("MyList") expect(type.first).to be_a(CollectionType) expect(type.first.types.size).to eq 1 expect(type.first.name).to eq "MyList" expect(type.first.types.first.name).to eq "String" end it "allows a collection type without a name" do type = parse("") expect(type.first.name).to eq "Array" end it "allows a fixed collection type without a name" do type = parse("(String)") expect(type.first.name).to eq "Array" end it "allows a hash collection type without a name" do type = parse("{K=>V}") expect(type.first.name).to eq "Hash" end it "does not accept two commas in a row" do parse_fail "A,,B" end it "does not accept two types not separated by a comma" do parse_fail "A B" end it "does not allow a comma without a following type" do parse_fail "A, " end it "fails on any unrecognized character" do parse_fail "$" end end describe ".explain" do it "parses an arbitrarily nested collection type" do explain = YARD::Tags::TypesExplainer.explain("ArrayV})>>") result = "an Array of (Strings or an Array of (Symbols or a List containing (a String followed by a Hash with keys made of (K's) and values of (V's))))" expect(explain).to eq result.delete("\n").squeeze(' ') end it "parses various examples" do expect = { "Fixnum, Foo, Object, true" => "a Fixnum; a Foo; an Object; true", "#read" => "an object that responds to #read", "Array" => "an Array of (Strings, Symbols or objects that respond to #read)", "Set" => "a Set of (Numbers)", "Array(String, Symbol)" => "an Array containing (a String followed by a Symbol)", "Hash{String => Symbol, Number}" => "a Hash with keys made of (Strings) and values of (Symbols or Numbers)", "Array, List(String, Symbol, #to_s), {Foo, Bar => Symbol, Number}" => "an Array of (Foos or Bars); a List containing (a String followed by a Symbol followed by an object that responds to #to_s); a Hash with keys made of (Foos or Bars) and values of (Symbols or Numbers)", "#weird_method?, #<=>, #!=" => "an object that responds to #weird_method?; an object that responds to #<=>; an object that responds to #!=" } expect.each do |input, expected| explain = YARD::Tags::TypesExplainer.explain(input) expect(explain).to eq expected.delete("\n").squeeze(' ') end end end end yard-0.9.12/spec/tags/library_spec.rb0000755000004100000410000000274613206751010017474 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::Tags::Library do def tag(docstring) Docstring.new(docstring).tags.first end describe "#see_tag" do it "takes a URL" do expect(tag("@see http://example.com").name).to eq "http://example.com" end it "takes an object path" do expect(tag("@see String#reverse").name).to eq "String#reverse" end it "takes a description after the url/object" do tag = tag("@see http://example.com An Example Site") expect(tag.name).to eq "http://example.com" expect(tag.text).to eq "An Example Site" end end describe ".define_tag" do it "allows 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) expect(Tags::Library.instance.method(:x_y_z_tag)).not_to be nil expect(Tags::Library.instance.method(:x_y_zz_tag)).not_to be nil expect(tag('@x.y.z foo bar').text).to eq 'foo bar' expect(tag('@x.y.zz foo(bar)').signature).to eq 'foo(bar)' end end describe "#tag.explain_types" do it "can explain tag types" do expect(tag("@return [A, B]").explain_types).to eq "an A; a B of (Strings)" end it "returns nil if no types present" do expect(tag("@return").explain_types).to eq nil end it "returns nil if types are not parseable" do expect(tag("@return [$]").explain_types).to eq nil end end end yard-0.9.12/spec/tags/default_tag_spec.rb0000755000004100000410000000054413206751010020301 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::Tags::DefaultTag do it "creates a tag with defaults" do o = YARD::Tags::DefaultTag.new('tagname', 'desc', ['types'], 'name', ['defaults']) expect(o.defaults).to eq ['defaults'] expect(o.tag_name).to eq 'tagname' expect(o.name).to eq 'name' expect(o.types).to eq ['types'] end end yard-0.9.12/spec/tags/overload_tag_spec.rb0000755000004100000410000000317013206751010020466 0ustar www-datawww-data# frozen_string_literal: true RSpec.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 "parses the first line as a method signature" do expect(@tag.signature).to eq "def bar(a, b = 1, &block)" expect(@tag.parameters).to eq [['a', nil], ['b', "1"], ['&block', nil]] end it "parses the rest of the text as a new Docstring" do expect(@tag.docstring).to be_instance_of(Docstring) expect(@tag.docstring).to eq "Hello world" end it "sets Docstring's object after #object= is called" do m = double(:object) @tag.object = m expect(@tag.docstring.object).to eq m end it "responds to #tag, #tags and #has_tag?" do @tag.object = double(:object) expect(@tag.tags.size).to eq 2 expect(@tag.tag(:param).name).to eq "a" expect(@tag.has_tag?(:return)).to be true end it "is not a CodeObjects::Base when not hooked up to an object" do @tag.object = nil expect(@tag.is_a?(CodeObjects::Base)).to be false end it "is a CodeObjects::Base when hooked up to an object" do @tag.object = double(:object) expect(@tag.object).to receive(:is_a?).at_least(3).times.with(CodeObjects::Base).and_return(true) expect(@tag.is_a?(CodeObjects::Base)).to be true expect(@tag.is_a?(CodeObjects::Base)).to be true expect(CodeObjects::Base === @tag).to be true end it "does not parse 'def' out of method name" do tag = Tags::OverloadTag.new(:overload, "default") expect(tag.signature).to eq "default" end end yard-0.9.12/spec/tags/directives_spec.rb0000755000004100000410000003341313206751010020164 0ustar www-datawww-data# frozen_string_literal: true def tag_parse(content, object = nil, handler = nil) @parser = DocstringParser.new @parser.parse(content, object, handler) @parser end RSpec.describe YARD::Tags::ParseDirective do describe "#call" do after { Registry.clear } it "parses if handler=nil but use file=(stdin)" do tag_parse %(@!parse # Docstring here def foo; end ) expect(Registry.at('#foo').docstring).to eq "Docstring here" expect(Registry.at('#foo').file).to eq '(stdin)' end it "allows parser type to be specified in type" do tag_parse %{@!parse [c] void Init_Foo() { rb_define_method(rb_cMyClass, "foo", foo, 1); } } expect(Registry.at('MyClass#foo')).not_to be nil end it "parses code in context of current handler" do src = <<-eof class A # @!parse # def foo; end eval "def foo; end" end eof parser = YARD::Parser::SourceParser.new parser.file = "myfile.rb" parser.parse(StringIO.new(src)) expect(Registry.at('A#foo').file).to eq 'myfile.rb' end end end RSpec.describe YARD::Tags::GroupDirective do describe "#call" do it "does nothing if handler=nil" do tag_parse("@!group foo") end it "sets group value in parser state (with handler)" do handler = OpenStruct.new(:extra_state => OpenStruct.new) tag_parse("@!group foo", nil, handler) expect(handler.extra_state.group).to eq 'foo' end end end RSpec.describe YARD::Tags::EndGroupDirective do describe "#call" do it "does nothing if handler=nil" do tag_parse("@!endgroup foo") end it "sets group value in parser state (with handler)" do handler = OpenStruct.new(:extra_state => OpenStruct.new(:group => "foo")) tag_parse("@!endgroup", nil, handler) expect(handler.extra_state.group).to be nil end end end RSpec.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'), :parser => OpenStruct.new(:file => "(stdin)", :line => 1), :statement => OpenStruct.new(:source => 'foo :a, :b, :c')) end after(:all) { Registry.clear } describe "#call" do it "defines new macro when [new] is provided" do tag_parse("@!macro [new] foo\n foo") expect(CodeObjects::MacroObject.find('foo').macro_data).to eq 'foo' end it "defines new macro if text block is provided" do tag_parse("@!macro bar\n bar") expect(CodeObjects::MacroObject.find('bar').macro_data).to eq 'bar' end it "expands macros and return #expanded_text to tag parser" do tag_parse("@!macro [new] foo\n foo") expect(tag_parse("@!macro foo").text).to eq 'foo' end it "does not expand new macro if docstring is unattached" do expect(tag_parse("@!macro [new] foo\n foo").text).not_to eq 'foo' end it "expands new anonymous macro even if docstring is unattached" do expect(tag_parse("@!macro\n foo").text).to eq 'foo' end it "allows multiple macros to be expanded" do tag_parse("@!macro [new] foo\n foo") tag_parse("@!macro bar\n bar") expect(tag_parse("@!macro foo\n@!macro bar").text).to eq "foo\nbar" end it "allows anonymous macros" do tag_parse("@!macro\n a b c", nil, handler) expect(@parser.text).to eq 'a b c' end it "expands call_params and caller_method using $N when handler is provided" do tag_parse("@!macro\n $1 $2 $3", nil, handler) expect(@parser.text).to eq 'a b c' end it "attaches macro to method if one exists" do tag_parse("@!macro [attach] attached\n $1 $2 $3", nil, handler) macro = CodeObjects::MacroObject.find('attached') expect(macro.method_object).to eq P('Foo::Bar.foo') end it "does not expand new attached macro if defined on class method" do baz = CodeObjects::MethodObject.new(P('Foo::Bar'), :baz, :class) expect(baz.visibility).to eq :public tag_parse("@!macro [attach] attached2\n @!visibility private", baz, handler) macro = CodeObjects::MacroObject.find('attached2') expect(macro.method_object).to eq P('Foo::Bar.baz') expect(baz.visibility).to eq :public end it "expands 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 expect(doc).to eq 'expanded_data' end it "does not attach macros to class/modules but creates macro" do YARD::Registry.clear YARD.parse_string "module Foo; end" tag_parse("@!macro [attach] attached4\n $1 $2 $3", YARD::Registry.at('Foo'), handler) macro = CodeObjects::MacroObject.find('attached4') expect(macro.method_object).to eq nil expect(log.io.string).to match(/Attaching macros to non-methods is unsupported/) end it "does not attempt to expand macro values if handler = nil" do tag_parse("@!macro [attach] xyz\n $1 $2 $3") end end end RSpec.describe YARD::Tags::MethodDirective do describe "#call" do after { Registry.clear } it "uses entire docstring if no indented data is found" do YARD.parse_string <<-eof class Foo # @!method foo # @!method bar # @!scope class end eof expect(Registry.at('Foo.foo')).to be_a(CodeObjects::MethodObject) expect(Registry.at('Foo.bar')).to be_a(CodeObjects::MethodObject) end it "handles 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') expect(foo.docstring).to eq "Docstring here" expect(foo.docstring.tag(:return)).not_to be nil expect(foo.tag(:param)).to be nil end it "executes 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') expect(foo.visibility).to eq :private bar = Registry.at('Foo#bar') expect(bar.visibility).to eq :public end it "is 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') expect(foo1.docstring).to eq 'Docstring1' expect(foo2.docstring).to eq 'Docstring2' expect(foo3.docstring).to eq 'Docstring3' end it "defines 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 expect(Registry.at('Foo::Bar#foo').docstring).to eq 'Docstring1' expect(Registry.at('Foo::Bar#bar').docstring).to eq 'Docstring2' end it "sets 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| expect(Registry.at("Foo.#{name}")).to be_a(CodeObjects::MethodObject) end end it "defines parameters from signature" do YARD.parse_string <<-eof # @!method foo(a, b, c = nil) eof expect(Registry.at('#foo').parameters).to eq [['a', nil], ['b', nil], ['c', 'nil']] end it "is 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') expect(foo_c).not_to be nil expect(foo_i).not_to be nil expect(foo_c).to be_module_function expect(foo_c.docstring).to eq foo_i.docstring expect(foo_c.tag(:return).text).to eq foo_i.tag(:return).text end end end RSpec.describe YARD::Tags::AttributeDirective do describe "#call" do after { Registry.clear } it "uses entire docstring if no indented data is found" do YARD.parse_string <<-eof class Foo # @!attribute foo # @!attribute bar # @!scope class end eof expect(Registry.at('Foo.foo')).to be_reader expect(Registry.at('Foo.bar')).to be_reader end it "handles 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') expect(foo.is_attribute?).to be true expect(foo.docstring).to eq "Docstring here" expect(foo.docstring.tag(:return)).not_to be nil expect(foo.tag(:param)).to be nil end it "is 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=') expect(foo1).to be_reader expect(foo2).to be_writer expect(foo3).to be_reader expect(foo1.docstring).to eq 'Docstring1' expect(foo2.docstring).to eq 'Docstring2' expect(foo3.docstring).to eq 'Docstring3' expect(foo4).to be_writer expect(foo1.attr_info[:write]).to be nil expect(foo2.attr_info[:read]).to be nil end it "defines 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 expect(Registry.at('Foo::Bar#foo')).to be_reader expect(Registry.at('Foo::Bar#bar')).to be_reader end end it "sets 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| expect(Registry.at("Foo.#{name}")).to be_reader end end end RSpec.describe YARD::Tags::ScopeDirective do describe "#call" do after { Registry.clear } it "sets state on tag parser if object = nil" do tag_parse("@!scope class") expect(@parser.state.scope).to eq :class end it "sets state on tag parser if object is namespace" do object = CodeObjects::ClassObject.new(:root, 'Foo') tag_parse("@!scope class", object) expect(object[:scope]).to be nil expect(@parser.state.scope).to eq :class end it "sets scope on object if object is a method object" do object = CodeObjects::MethodObject.new(:root, 'foo') tag_parse("@!scope class", object) expect(object.scope).to eq :class end %w(class instance module).each do |type| it "allows #{type} as value" do tag_parse("@!scope #{type}") expect(@parser.state.scope).to eq type.to_sym end end %w(invalid foo FOO CLASS INSTANCE).each do |type| it "does not allow #{type} as value" do tag_parse("@!scope #{type}") expect(@parser.state.scope).to be nil end end end end RSpec.describe YARD::Tags::VisibilityDirective do describe "#call" do after { Registry.clear } it "sets visibility on tag parser if object = nil" do tag_parse("@!visibility private") expect(@parser.state.visibility).to eq :private end it "sets state on tag parser if object is namespace" do object = CodeObjects::ClassObject.new(:root, 'Foo') tag_parse("@!visibility protected", object) expect(object.visibility).to eq :protected expect(@parser.state.visibility).to be nil end it "sets visibility on object if object is a method object" do object = CodeObjects::MethodObject.new(:root, 'foo') tag_parse("@!visibility private", object) expect(object.visibility).to eq :private end %w(public private protected).each do |type| it "allows #{type} as value" do tag_parse("@!visibility #{type}") expect(@parser.state.visibility).to eq type.to_sym end end %w(invalid foo FOO PRIVATE INSTANCE).each do |type| it "does not allow #{type} as value" do tag_parse("@!visibility #{type}") expect(@parser.state.visibility).to 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| expect(Registry.at("Foo##{name}").visibility).to eq :private end end if YARD::Parser::SourceParser.parser_type == :ruby end end yard-0.9.12/spec/tags/ref_tag_list_spec.rb0000755000004100000410000000324413206751010020464 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::Tags::RefTagList do before { YARD::Registry.clear } it "accepts symbol or string as owner's path and convert it into a proxy" do t = Tags::RefTagList.new('author', :String) expect(t.owner).to eq P(:String) end it "accepts proxy object as owner" do t = Tags::RefTagList.new('author', P(:String)) expect(t.owner).to eq P(:String) end it "returns 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) expect(ref.tags).to eq [t] expect(ref.tags.first.text).to eq 'foo' end it "returns 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') expect(ref.tags).to eq [p1, p2] expect(ref.tags.first.text).to eq '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| expect(t).to be_kind_of(Tags::RefTag) expect(t.owner).to eq o end end end yard-0.9.12/spec/examples.txt0000755000004100000410000054526613206751010016123 0ustar www-datawww-dataexample_id | status | run_time | -------------------------------------------------------------------- | ------ | --------------- | ./spec/cli/command_parser_spec.rb[1:1:1] | passed | 0.04728 seconds | ./spec/cli/command_parser_spec.rb[1:1:2] | passed | 0.00039 seconds | ./spec/cli/command_parser_spec.rb[1:1:3] | passed | 0.00033 seconds | ./spec/cli/command_parser_spec.rb[1:1:4] | passed | 0.00028 seconds | ./spec/cli/command_parser_spec.rb[1:1:5] | passed | 0.00042 seconds | ./spec/cli/command_spec.rb[1:1:1] | passed | 0.00696 seconds | ./spec/cli/command_spec.rb[1:1:2] | passed | 0.00072 seconds | ./spec/cli/command_spec.rb[1:1:3] | passed | 0.01534 seconds | ./spec/cli/config_spec.rb[1:1:1] | passed | 0.00181 seconds | ./spec/cli/config_spec.rb[1:2:1] | passed | 0.00093 seconds | ./spec/cli/config_spec.rb[1:3:1] | passed | 0.00084 seconds | ./spec/cli/config_spec.rb[1:3:2] | passed | 0.00083 seconds | ./spec/cli/config_spec.rb[1:3:3] | passed | 0.00148 seconds | ./spec/cli/config_spec.rb[1:3:4] | passed | 0.00074 seconds | ./spec/cli/config_spec.rb[1:3:5] | passed | 0.00077 seconds | ./spec/cli/config_spec.rb[1:3:6] | passed | 0.00082 seconds | ./spec/cli/config_spec.rb[1:3:7] | passed | 0.00126 seconds | ./spec/cli/config_spec.rb[1:3:8] | passed | 0.00079 seconds | ./spec/cli/config_spec.rb[1:3:9] | passed | 0.00074 seconds | ./spec/cli/config_spec.rb[1:3:10] | passed | 0.00079 seconds | ./spec/cli/config_spec.rb[1:4:1] | passed | 0.00081 seconds | ./spec/cli/config_spec.rb[1:4:2] | passed | 0.00078 seconds | ./spec/cli/config_spec.rb[1:4:3] | passed | 0.00077 seconds | ./spec/cli/config_spec.rb[1:4:4] | passed | 0.00114 seconds | ./spec/cli/config_spec.rb[1:4:5] | passed | 0.00093 seconds | ./spec/cli/config_spec.rb[1:4:6] | passed | 0.00113 seconds | ./spec/cli/config_spec.rb[1:4:7] | passed | 0.00091 seconds | ./spec/cli/config_spec.rb[1:4:8] | passed | 0.00091 seconds | ./spec/cli/config_spec.rb[1:4:9] | passed | 0.00089 seconds | ./spec/cli/config_spec.rb[1:4:10] | passed | 0.00085 seconds | ./spec/cli/diff_spec.rb[1:1:1] | passed | 0.00111 seconds | ./spec/cli/diff_spec.rb[1:2:1] | passed | 0.03534 seconds | ./spec/cli/diff_spec.rb[1:2:2] | passed | 0.0055 seconds | ./spec/cli/diff_spec.rb[1:2:3] | passed | 0.01205 seconds | ./spec/cli/diff_spec.rb[1:2:4] | passed | 0.00583 seconds | ./spec/cli/diff_spec.rb[1:2:5] | passed | 0.00683 seconds | ./spec/cli/diff_spec.rb[1:2:6] | passed | 0.0063 seconds | ./spec/cli/diff_spec.rb[1:3:1] | passed | 0.15998 seconds | ./spec/cli/diff_spec.rb[1:3:2] | passed | 0.00139 seconds | ./spec/cli/diff_spec.rb[1:3:3] | passed | 0.00281 seconds | ./spec/cli/diff_spec.rb[1:3:4] | passed | 0.00158 seconds | ./spec/cli/diff_spec.rb[1:3:5] | passed | 0.00177 seconds | ./spec/cli/diff_spec.rb[1:3:6] | passed | 0.00123 seconds | ./spec/cli/display_spec.rb[1:1] | passed | 0.02256 seconds | ./spec/cli/display_spec.rb[1:2] | passed | 0.25579 seconds | ./spec/cli/display_spec.rb[1:3] | passed | 0.04214 seconds | ./spec/cli/gems_spec.rb[1:1:1] | passed | 0.00148 seconds | ./spec/cli/gems_spec.rb[1:1:2] | passed | 0.00101 seconds | ./spec/cli/gems_spec.rb[1:1:3] | passed | 0.00147 seconds | ./spec/cli/gems_spec.rb[1:1:4] | passed | 0.00144 seconds | ./spec/cli/gems_spec.rb[1:1:5] | passed | 0.00132 seconds | ./spec/cli/gems_spec.rb[1:1:6] | passed | 0.00077 seconds | ./spec/cli/gems_spec.rb[1:1:7] | passed | 0.001 seconds | ./spec/cli/graph_spec.rb[1:1] | passed | 0.01134 seconds | ./spec/cli/graph_spec.rb[1:2] | passed | 0.00486 seconds | ./spec/cli/help_spec.rb[1:1:1] | passed | 0.0004 seconds | ./spec/cli/help_spec.rb[1:1:2] | passed | 0.00015 seconds | ./spec/cli/help_spec.rb[1:1:3] | passed | 0.00027 seconds | ./spec/cli/i18n_spec.rb[1:1:1] | passed | 0.03329 seconds | ./spec/cli/i18n_spec.rb[1:1:2] | passed | 0.02044 seconds | ./spec/cli/i18n_spec.rb[1:2:1] | passed | 0.01729 seconds | ./spec/cli/i18n_spec.rb[1:2:2] | passed | 0.01026 seconds | ./spec/cli/i18n_spec.rb[1:2:3] | passed | 0.01138 seconds | ./spec/cli/i18n_spec.rb[1:2:4] | passed | 0.00985 seconds | ./spec/cli/i18n_spec.rb[1:3:1] | passed | 0.01231 seconds | ./spec/cli/i18n_spec.rb[1:4:1] | passed | 0.00052 seconds | ./spec/cli/i18n_spec.rb[1:4:2] | passed | 0.00047 seconds | ./spec/cli/i18n_spec.rb[1:4:3] | passed | 0.00054 seconds | ./spec/cli/list_spec.rb[1:1] | passed | 0.0002 seconds | ./spec/cli/markup_types_spec.rb[1:1] | passed | 0.0063 seconds | ./spec/cli/server_spec.rb[1:1:1] | passed | 0.00364 seconds | ./spec/cli/server_spec.rb[1:1:2] | passed | 0.00211 seconds | ./spec/cli/server_spec.rb[1:1:3] | passed | 0.00172 seconds | ./spec/cli/server_spec.rb[1:2:1] | passed | 0.00173 seconds | ./spec/cli/server_spec.rb[1:2:2] | passed | 0.0018 seconds | ./spec/cli/server_spec.rb[1:2:3] | passed | 0.00148 seconds | ./spec/cli/server_spec.rb[1:2:4] | passed | 0.00132 seconds | ./spec/cli/server_spec.rb[1:3:1] | passed | 0.00312 seconds | ./spec/cli/server_spec.rb[1:3:2] | passed | 0.00328 seconds | ./spec/cli/server_spec.rb[1:3:3] | passed | 0.00271 seconds | ./spec/cli/server_spec.rb[1:3:4] | passed | 0.00276 seconds | ./spec/cli/server_spec.rb[1:3:5] | passed | 0.00331 seconds | ./spec/cli/server_spec.rb[1:3:6] | passed | 0.00313 seconds | ./spec/cli/server_spec.rb[1:3:7] | passed | 0.04209 seconds | ./spec/cli/server_spec.rb[1:3:8] | passed | 0.0024 seconds | ./spec/cli/server_spec.rb[1:3:9] | passed | 0.00186 seconds | ./spec/cli/server_spec.rb[1:3:10] | passed | 0.00154 seconds | ./spec/cli/server_spec.rb[1:3:11] | passed | 0.00152 seconds | ./spec/cli/server_spec.rb[1:3:12] | passed | 0.00045 seconds | ./spec/cli/server_spec.rb[1:3:13] | passed | 0.00045 seconds | ./spec/cli/server_spec.rb[1:3:14] | passed | 0.00278 seconds | ./spec/cli/server_spec.rb[1:3:15] | passed | 0.00339 seconds | ./spec/cli/server_spec.rb[1:3:16] | passed | 0.00453 seconds | ./spec/cli/server_spec.rb[1:3:17] | passed | 0.00174 seconds | ./spec/cli/server_spec.rb[1:3:18] | passed | 0.00186 seconds | ./spec/cli/server_spec.rb[1:3:19] | passed | 0.00128 seconds | ./spec/cli/server_spec.rb[1:3:20] | passed | 0.00705 seconds | ./spec/cli/stats_spec.rb[1:1] | passed | 0.0167 seconds | ./spec/cli/stats_spec.rb[1:2] | passed | 0.01744 seconds | ./spec/cli/stats_spec.rb[1:3] | passed | 0.01693 seconds | ./spec/cli/stats_spec.rb[1:4] | passed | 0.0167 seconds | ./spec/cli/stats_spec.rb[1:5] | passed | 0.01755 seconds | ./spec/cli/yardoc_spec.rb[1:1:1] | passed | 0.01297 seconds | ./spec/cli/yardoc_spec.rb[1:1:2] | passed | 0.0138 seconds | ./spec/cli/yardoc_spec.rb[1:1:3] | passed | 0.01926 seconds | ./spec/cli/yardoc_spec.rb[1:1:4] | passed | 0.01651 seconds | ./spec/cli/yardoc_spec.rb[1:1:5] | passed | 0.01648 seconds | ./spec/cli/yardoc_spec.rb[1:1:6] | passed | 0.01415 seconds | ./spec/cli/yardoc_spec.rb[1:1:7] | passed | 0.01343 seconds | ./spec/cli/yardoc_spec.rb[1:1:8] | passed | 0.01353 seconds | ./spec/cli/yardoc_spec.rb[1:1:9] | passed | 0.01351 seconds | ./spec/cli/yardoc_spec.rb[1:1:10] | passed | 0.01305 seconds | ./spec/cli/yardoc_spec.rb[1:1:11] | passed | 0.01261 seconds | ./spec/cli/yardoc_spec.rb[1:1:12] | passed | 0.01311 seconds | ./spec/cli/yardoc_spec.rb[1:1:13] | passed | 0.01287 seconds | ./spec/cli/yardoc_spec.rb[1:1:14] | passed | 0.01894 seconds | ./spec/cli/yardoc_spec.rb[1:1:15] | passed | 0.01303 seconds | ./spec/cli/yardoc_spec.rb[1:2:1] | passed | 0.00556 seconds | ./spec/cli/yardoc_spec.rb[1:2:2] | passed | 0.00575 seconds | ./spec/cli/yardoc_spec.rb[1:2:3] | passed | 0.00521 seconds | ./spec/cli/yardoc_spec.rb[1:2:4] | passed | 0.00589 seconds | ./spec/cli/yardoc_spec.rb[1:2:5] | passed | 0.0056 seconds | ./spec/cli/yardoc_spec.rb[1:2:6] | passed | 0.01946 seconds | ./spec/cli/yardoc_spec.rb[1:2:7] | passed | 0.00909 seconds | ./spec/cli/yardoc_spec.rb[1:2:8] | passed | 0.01244 seconds | ./spec/cli/yardoc_spec.rb[1:2:9] | passed | 0.01081 seconds | ./spec/cli/yardoc_spec.rb[1:2:10] | passed | 0.00685 seconds | ./spec/cli/yardoc_spec.rb[1:2:11] | passed | 0.00613 seconds | ./spec/cli/yardoc_spec.rb[1:2:12] | passed | 0.00584 seconds | ./spec/cli/yardoc_spec.rb[1:2:13] | passed | 0.00573 seconds | ./spec/cli/yardoc_spec.rb[1:2:14] | passed | 0.0054 seconds | ./spec/cli/yardoc_spec.rb[1:2:15] | passed | 0.00579 seconds | ./spec/cli/yardoc_spec.rb[1:2:16] | passed | 0.00554 seconds | ./spec/cli/yardoc_spec.rb[1:2:17] | passed | 0.01181 seconds | ./spec/cli/yardoc_spec.rb[1:3:1] | passed | 0.00757 seconds | ./spec/cli/yardoc_spec.rb[1:3:2] | passed | 0.01236 seconds | ./spec/cli/yardoc_spec.rb[1:3:3] | passed | 0.00828 seconds | ./spec/cli/yardoc_spec.rb[1:3:4] | passed | 0.0115 seconds | ./spec/cli/yardoc_spec.rb[1:3:5] | passed | 0.00645 seconds | ./spec/cli/yardoc_spec.rb[1:3:6] | passed | 0.00655 seconds | ./spec/cli/yardoc_spec.rb[1:3:7] | passed | 0.00661 seconds | ./spec/cli/yardoc_spec.rb[1:3:8] | passed | 0.0065 seconds | ./spec/cli/yardoc_spec.rb[1:3:9] | passed | 0.00704 seconds | ./spec/cli/yardoc_spec.rb[1:3:10] | passed | 0.00878 seconds | ./spec/cli/yardoc_spec.rb[1:3:11] | passed | 0.0072 seconds | ./spec/cli/yardoc_spec.rb[1:3:12] | passed | 0.00651 seconds | ./spec/cli/yardoc_spec.rb[1:3:13:1] | passed | 0.00891 seconds | ./spec/cli/yardoc_spec.rb[1:3:13:2] | passed | 0.00866 seconds | ./spec/cli/yardoc_spec.rb[1:3:13:3] | passed | 0.02736 seconds | ./spec/cli/yardoc_spec.rb[1:3:13:4] | passed | 0.00832 seconds | ./spec/cli/yardoc_spec.rb[1:3:13:5] | passed | 0.01739 seconds | ./spec/cli/yardoc_spec.rb[1:3:14:1] | passed | 0.00542 seconds | ./spec/cli/yardoc_spec.rb[1:3:15:1] | passed | 0.00662 seconds | ./spec/cli/yardoc_spec.rb[1:4:1] | passed | 0.0081 seconds | ./spec/cli/yardoc_spec.rb[1:4:2] | passed | 0.00815 seconds | ./spec/cli/yardoc_spec.rb[1:4:3] | passed | 0.01214 seconds | ./spec/cli/yardoc_spec.rb[1:4:4] | passed | 0.00766 seconds | ./spec/cli/yardoc_spec.rb[1:4:5] | passed | 0.01402 seconds | ./spec/cli/yardoc_spec.rb[1:5:1] | passed | 0.00737 seconds | ./spec/cli/yardoc_spec.rb[1:5:2] | passed | 0.0081 seconds | ./spec/cli/yardoc_spec.rb[1:6:1] | passed | 0.00591 seconds | ./spec/cli/yardoc_spec.rb[1:6:2] | passed | 0.00606 seconds | ./spec/cli/yardoc_spec.rb[1:6:3] | passed | 0.0061 seconds | ./spec/cli/yardoc_spec.rb[1:6:4] | passed | 0.00868 seconds | ./spec/cli/yardoc_spec.rb[1:6:5] | passed | 0.00634 seconds | ./spec/cli/yardoc_spec.rb[1:6:6] | passed | 0.00804 seconds | ./spec/cli/yardoc_spec.rb[1:7:1] | passed | 0.00982 seconds | ./spec/cli/yardoc_spec.rb[1:7:2] | passed | 0.00979 seconds | ./spec/cli/yardoc_spec.rb[1:7:3] | passed | 0.01009 seconds | ./spec/cli/yardoc_spec.rb[1:7:4] | passed | 0.01216 seconds | ./spec/cli/yardoc_spec.rb[1:8:1] | passed | 0.00911 seconds | ./spec/cli/yardoc_spec.rb[1:8:2] | passed | 0.00827 seconds | ./spec/cli/yardoc_spec.rb[1:8:3] | passed | 0.01152 seconds | ./spec/cli/yardoc_spec.rb[1:8:4] | passed | 0.00723 seconds | ./spec/cli/yardoc_spec.rb[1:9:1] | passed | 0.00525 seconds | ./spec/cli/yardoc_spec.rb[1:9:2] | passed | 0.00549 seconds | ./spec/cli/yardoc_spec.rb[1:9:3] | passed | 0.00589 seconds | ./spec/cli/yardoc_spec.rb[1:9:4] | passed | 0.00724 seconds | ./spec/cli/yardoc_spec.rb[1:9:5] | passed | 0.00634 seconds | ./spec/cli/yardoc_spec.rb[1:9:6] | passed | 0.00565 seconds | ./spec/cli/yardoc_spec.rb[1:9:7] | passed | 0.00577 seconds | ./spec/cli/yardoc_spec.rb[1:9:8] | passed | 0.00464 seconds | ./spec/cli/yardoc_spec.rb[1:9:9] | passed | 0.00477 seconds | ./spec/cli/yardoc_spec.rb[1:9:10] | passed | 0.00614 seconds | ./spec/cli/yardoc_spec.rb[1:10:1] | passed | 0.00576 seconds | ./spec/cli/yardoc_spec.rb[1:11:1] | passed | 0.00561 seconds | ./spec/cli/yardoc_spec.rb[1:11:2] | passed | 0.00573 seconds | ./spec/cli/yardoc_spec.rb[1:11:3] | passed | 0.00647 seconds | ./spec/cli/yardoc_spec.rb[1:11:4] | passed | 0.00606 seconds | ./spec/cli/yardoc_spec.rb[1:11:5] | passed | 0.00613 seconds | ./spec/cli/yardoc_spec.rb[1:11:6] | passed | 0.00634 seconds | ./spec/cli/yardoc_spec.rb[1:11:7] | passed | 0.00636 seconds | ./spec/cli/yardoc_spec.rb[1:11:8] | passed | 0.00664 seconds | ./spec/cli/yardoc_spec.rb[1:11:9] | passed | 0.00636 seconds | ./spec/cli/yardoc_spec.rb[1:11:10] | passed | 0.00554 seconds | ./spec/cli/yardoc_spec.rb[1:11:11] | passed | 0.00554 seconds | ./spec/cli/yardoc_spec.rb[1:12:1] | passed | 0.0103 seconds | ./spec/cli/yardoc_spec.rb[1:12:2] | passed | 0.00637 seconds | ./spec/cli/yardoc_spec.rb[1:12:3] | passed | 0.01071 seconds | ./spec/cli/yardoc_spec.rb[1:13:1] | passed | 0.00767 seconds | ./spec/cli/yardoc_spec.rb[1:13:2] | passed | 0.00563 seconds | ./spec/cli/yardoc_spec.rb[1:13:3] | passed | 0.01191 seconds | ./spec/cli/yardoc_spec.rb[1:13:4] | passed | 0.01203 seconds | ./spec/cli/yardoc_spec.rb[1:13:5] | passed | 0.01214 seconds | ./spec/cli/yardoc_spec.rb[1:14:1] | passed | 0.00072 seconds | ./spec/cli/yardoc_spec.rb[1:14:2] | passed | 0.00057 seconds | ./spec/cli/yardoc_spec.rb[1:14:3] | passed | 0.0007 seconds | ./spec/cli/yardoc_spec.rb[1:14:4] | passed | 0.00593 seconds | ./spec/cli/yardoc_spec.rb[1:14:5] | passed | 0.00611 seconds | ./spec/cli/yardoc_spec.rb[1:14:6:1] | passed | 0.00914 seconds | ./spec/cli/yardoc_spec.rb[1:14:6:2] | passed | 0.00624 seconds | ./spec/cli/yri_spec.rb[1:1:1] | passed | 0.01284 seconds | ./spec/cli/yri_spec.rb[1:1:2] | passed | 0.00973 seconds | ./spec/cli/yri_spec.rb[1:2:1] | passed | 0.01008 seconds | ./spec/cli/yri_spec.rb[1:3:1] | passed | 0.01914 seconds | ./spec/cli/yri_spec.rb[1:3:2] | passed | 0.01961 seconds | ./spec/cli/yri_spec.rb[1:4:1] | passed | 0.01135 seconds | ./spec/cli/yri_spec.rb[1:4:2] | passed | 0.0103 seconds | ./spec/cli/yri_spec.rb[1:4:3] | passed | 0.01037 seconds | ./spec/cli/yri_spec.rb[1:4:4] | passed | 0.01249 seconds | ./spec/code_objects/base_spec.rb[1:1] | passed | 0.00017 seconds | ./spec/code_objects/base_spec.rb[1:2] | passed | 0.00034 seconds | ./spec/code_objects/base_spec.rb[1:3] | passed | 0.00521 seconds | ./spec/code_objects/base_spec.rb[1:4] | passed | 0.00194 seconds | ./spec/code_objects/base_spec.rb[1:5] | passed | 0.00255 seconds | ./spec/code_objects/base_spec.rb[1:6] | passed | 0.00035 seconds | ./spec/code_objects/base_spec.rb[1:7] | passed | 0.00033 seconds | ./spec/code_objects/base_spec.rb[1:8] | passed | 0.00011 seconds | ./spec/code_objects/base_spec.rb[1:9] | passed | 0.00015 seconds | ./spec/code_objects/base_spec.rb[1:10] | passed | 0.00011 seconds | ./spec/code_objects/base_spec.rb[1:11] | passed | 0.00014 seconds | ./spec/code_objects/base_spec.rb[1:12] | passed | 0.00016 seconds | ./spec/code_objects/base_spec.rb[1:13:1] | passed | 0.00015 seconds | ./spec/code_objects/base_spec.rb[1:13:2] | passed | 0.00027 seconds | ./spec/code_objects/base_spec.rb[1:14] | passed | 0.00013 seconds | ./spec/code_objects/base_spec.rb[1:15] | passed | 0.00027 seconds | ./spec/code_objects/base_spec.rb[1:16] | passed | 0.00132 seconds | ./spec/code_objects/base_spec.rb[1:17] | passed | 0.00599 seconds | ./spec/code_objects/base_spec.rb[1:18] | passed | 0.00062 seconds | ./spec/code_objects/base_spec.rb[1:19] | passed | 0.00056 seconds | ./spec/code_objects/base_spec.rb[1:20] | passed | 0.00145 seconds | ./spec/code_objects/base_spec.rb[1:21] | passed | 0.0022 seconds | ./spec/code_objects/base_spec.rb[1:22] | passed | 0.00116 seconds | ./spec/code_objects/base_spec.rb[1:23:1] | passed | 0.0004 seconds | ./spec/code_objects/base_spec.rb[1:23:2] | passed | 0.00032 seconds | ./spec/code_objects/base_spec.rb[1:24:1] | passed | 0.00012 seconds | ./spec/code_objects/base_spec.rb[1:25:1] | passed | 0.00119 seconds | ./spec/code_objects/base_spec.rb[1:25:2] | passed | 0.00063 seconds | ./spec/code_objects/base_spec.rb[1:25:3] | passed | 0.00219 seconds | ./spec/code_objects/base_spec.rb[1:25:4] | passed | 0.00631 seconds | ./spec/code_objects/base_spec.rb[1:25:5] | passed | 0.00111 seconds | ./spec/code_objects/base_spec.rb[1:25:6] | passed | 0.00121 seconds | ./spec/code_objects/base_spec.rb[1:25:7] | passed | 0.00063 seconds | ./spec/code_objects/base_spec.rb[1:25:8] | passed | 0.00212 seconds | ./spec/code_objects/base_spec.rb[1:26:1] | passed | 0.0003 seconds | ./spec/code_objects/base_spec.rb[1:26:2] | passed | 0.00037 seconds | ./spec/code_objects/base_spec.rb[1:26:3] | passed | 0.00022 seconds | ./spec/code_objects/base_spec.rb[1:26:4] | passed | 0.00646 seconds | ./spec/code_objects/base_spec.rb[1:27:1] | passed | 0.00047 seconds | ./spec/code_objects/base_spec.rb[1:27:2] | passed | 0.00064 seconds | ./spec/code_objects/base_spec.rb[1:27:3:1] | passed | 0.00081 seconds | ./spec/code_objects/base_spec.rb[1:27:3:2] | passed | 0.00077 seconds | ./spec/code_objects/base_spec.rb[1:28:1] | passed | 0.00028 seconds | ./spec/code_objects/base_spec.rb[1:29:1] | passed | 0.00221 seconds | ./spec/code_objects/base_spec.rb[1:29:2] | passed | 0.00054 seconds | ./spec/code_objects/base_spec.rb[1:29:3] | passed | 0.00087 seconds | ./spec/code_objects/base_spec.rb[1:29:4] | passed | 0.00121 seconds | ./spec/code_objects/class_object_spec.rb[1:1:1] | passed | 0.00073 seconds | ./spec/code_objects/class_object_spec.rb[1:1:2] | passed | 0.00072 seconds | ./spec/code_objects/class_object_spec.rb[1:1:3] | passed | 0.00066 seconds | ./spec/code_objects/class_object_spec.rb[1:1:4] | passed | 0.00036 seconds | ./spec/code_objects/class_object_spec.rb[1:2:1] | passed | 0.00196 seconds | ./spec/code_objects/class_object_spec.rb[1:2:2] | passed | 0.0003 seconds | ./spec/code_objects/class_object_spec.rb[1:2:3] | passed | 0.00412 seconds | ./spec/code_objects/class_object_spec.rb[1:2:4] | passed | 0.00193 seconds | ./spec/code_objects/class_object_spec.rb[1:2:5] | passed | 0.00123 seconds | ./spec/code_objects/class_object_spec.rb[1:3:1] | passed | 0.00221 seconds | ./spec/code_objects/class_object_spec.rb[1:3:2] | passed | 0.00014 seconds | ./spec/code_objects/class_object_spec.rb[1:3:3] | passed | 0.001 seconds | ./spec/code_objects/class_object_spec.rb[1:3:4] | passed | 0.00102 seconds | ./spec/code_objects/class_object_spec.rb[1:3:5] | passed | 0.00022 seconds | ./spec/code_objects/class_object_spec.rb[1:3:6] | passed | 0.00016 seconds | ./spec/code_objects/class_object_spec.rb[1:3:7] | passed | 0.00078 seconds | ./spec/code_objects/class_object_spec.rb[1:3:8] | passed | 0.00124 seconds | ./spec/code_objects/class_object_spec.rb[1:3:9] | passed | 0.00125 seconds | ./spec/code_objects/code_object_list_spec.rb[1:1:1] | passed | 0.0007 seconds | ./spec/code_objects/code_object_list_spec.rb[1:2] | passed | 0.00023 seconds | ./spec/code_objects/code_object_list_spec.rb[1:3] | passed | 0.00071 seconds | ./spec/code_objects/constants_spec.rb[1:1:1] | passed | 0.00008 seconds | ./spec/code_objects/constants_spec.rb[1:2:1] | passed | 0.00009 seconds | ./spec/code_objects/constants_spec.rb[1:3:1] | passed | 0.00008 seconds | ./spec/code_objects/constants_spec.rb[1:4:1] | passed | 0.00011 seconds | ./spec/code_objects/constants_spec.rb[1:5:1] | passed | 0.00011 seconds | ./spec/code_objects/constants_spec.rb[1:5:2] | passed | 0.00007 seconds | ./spec/code_objects/constants_spec.rb[1:6:1] | passed | 0.00028 seconds | ./spec/code_objects/constants_spec.rb[1:7:1] | passed | 0.00046 seconds | ./spec/code_objects/constants_spec.rb[1:7:2] | passed | 0.00023 seconds | ./spec/code_objects/constants_spec.rb[1:8:1] | passed | 0.00007 seconds | ./spec/code_objects/constants_spec.rb[1:9:1] | passed | 0.00023 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:1:1] | passed | 0.00056 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:1:2] | passed | 0.00019 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:1:3] | passed | 0.00012 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:1:4] | passed | 0.00023 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:1:5] | passed | 0.00012 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:1:6] | passed | 0.00013 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:1:7] | passed | 0.0001 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:1:8] | passed | 0.00015 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:1:9] | passed | 0.0001 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:1:10] | passed | 0.0001 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:1:11] | passed | 0.00011 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:1:12] | passed | 0.0001 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:1:13] | passed | 0.00014 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:1:14] | passed | 0.00009 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:1:15] | passed | 0.00034 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:1:16] | passed | 0.00911 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:1:17] | passed | 0.00043 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:2:1] | passed | 0.00008 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:3:1] | passed | 0.00017 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:3:2] | passed | 0.00009 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:4:1] | passed | 0.00028 seconds | ./spec/code_objects/extra_file_object_spec.rb[1:5:1] | passed | 0.00531 seconds | ./spec/code_objects/macro_object_spec.rb[1:1:1] | passed | 0.00025 seconds | ./spec/code_objects/macro_object_spec.rb[1:1:2] | passed | 0.00016 seconds | ./spec/code_objects/macro_object_spec.rb[1:1:3] | passed | 0.00015 seconds | ./spec/code_objects/macro_object_spec.rb[1:1:4:1] | passed | 0.00065 seconds | ./spec/code_objects/macro_object_spec.rb[1:2:1] | passed | 0.00015 seconds | ./spec/code_objects/macro_object_spec.rb[1:2:2] | passed | 0.00012 seconds | ./spec/code_objects/macro_object_spec.rb[1:3:1] | passed | 0.00014 seconds | ./spec/code_objects/macro_object_spec.rb[1:3:2] | passed | 0.00017 seconds | ./spec/code_objects/macro_object_spec.rb[1:4:1] | passed | 0.0002 seconds | ./spec/code_objects/macro_object_spec.rb[1:4:2] | passed | 0.00032 seconds | ./spec/code_objects/macro_object_spec.rb[1:4:3] | passed | 0.00037 seconds | ./spec/code_objects/macro_object_spec.rb[1:4:4] | passed | 0.0005 seconds | ./spec/code_objects/macro_object_spec.rb[1:4:5] | passed | 0.00033 seconds | ./spec/code_objects/macro_object_spec.rb[1:4:6] | passed | 0.00029 seconds | ./spec/code_objects/macro_object_spec.rb[1:5:1] | passed | 0.00015 seconds | ./spec/code_objects/macro_object_spec.rb[1:5:2] | passed | 0.00016 seconds | ./spec/code_objects/macro_object_spec.rb[1:5:3] | passed | 0.00013 seconds | ./spec/code_objects/macro_object_spec.rb[1:5:4] | passed | 0.0001 seconds | ./spec/code_objects/macro_object_spec.rb[1:5:5] | passed | 0.00014 seconds | ./spec/code_objects/macro_object_spec.rb[1:5:6] | passed | 0.0001 seconds | ./spec/code_objects/macro_object_spec.rb[1:5:7] | passed | 0.00012 seconds | ./spec/code_objects/macro_object_spec.rb[1:5:8] | passed | 0.00016 seconds | ./spec/code_objects/macro_object_spec.rb[1:6:1] | passed | 0.00013 seconds | ./spec/code_objects/method_object_spec.rb[1:1:1] | passed | 0.00022 seconds | ./spec/code_objects/method_object_spec.rb[1:2:1] | passed | 0.00018 seconds | ./spec/code_objects/method_object_spec.rb[1:3:1] | passed | 0.00023 seconds | ./spec/code_objects/method_object_spec.rb[1:4:1] | passed | 0.00022 seconds | ./spec/code_objects/method_object_spec.rb[1:5] | passed | 0.00025 seconds | ./spec/code_objects/method_object_spec.rb[1:6] | passed | 0.00021 seconds | ./spec/code_objects/method_object_spec.rb[1:7] | passed | 0.0002 seconds | ./spec/code_objects/method_object_spec.rb[1:8] | passed | 0.00018 seconds | ./spec/code_objects/method_object_spec.rb[1:9] | passed | 0.00034 seconds | ./spec/code_objects/method_object_spec.rb[1:10:1] | passed | 0.00032 seconds | ./spec/code_objects/method_object_spec.rb[1:10:2] | passed | 0.00021 seconds | ./spec/code_objects/method_object_spec.rb[1:11:1] | passed | 0.00025 seconds | ./spec/code_objects/method_object_spec.rb[1:12:1] | passed | 0.00017 seconds | ./spec/code_objects/method_object_spec.rb[1:12:2] | passed | 0.00044 seconds | ./spec/code_objects/method_object_spec.rb[1:12:3] | passed | 0.00021 seconds | ./spec/code_objects/method_object_spec.rb[1:13:1] | passed | 0.00024 seconds | ./spec/code_objects/method_object_spec.rb[1:14:1] | passed | 0.00021 seconds | ./spec/code_objects/method_object_spec.rb[1:15:1] | passed | 0.00096 seconds | ./spec/code_objects/method_object_spec.rb[1:15:2] | passed | 0.00027 seconds | ./spec/code_objects/method_object_spec.rb[1:15:3] | passed | 0.00024 seconds | ./spec/code_objects/method_object_spec.rb[1:16:1] | passed | 0.00348 seconds | ./spec/code_objects/method_object_spec.rb[1:16:2] | passed | 0.00218 seconds | ./spec/code_objects/method_object_spec.rb[1:16:3] | passed | 0.00171 seconds | ./spec/code_objects/method_object_spec.rb[1:16:4] | passed | 0.00146 seconds | ./spec/code_objects/module_object_spec.rb[1:1:1] | passed | 0.00197 seconds | ./spec/code_objects/module_object_spec.rb[1:1:2] | passed | 0.00078 seconds | ./spec/code_objects/module_object_spec.rb[1:1:3] | passed | 0.00123 seconds | ./spec/code_objects/module_object_spec.rb[1:1:4] | passed | 0.0007 seconds | ./spec/code_objects/module_object_spec.rb[1:1:5] | passed | 0.00064 seconds | ./spec/code_objects/module_object_spec.rb[1:1:6] | passed | 0.00075 seconds | ./spec/code_objects/module_object_spec.rb[1:2:1] | passed | 0.00055 seconds | ./spec/code_objects/module_object_spec.rb[1:2:2] | passed | 0.00045 seconds | ./spec/code_objects/module_object_spec.rb[1:2:3] | passed | 0.00134 seconds | ./spec/code_objects/module_object_spec.rb[1:2:4] | passed | 0.00049 seconds | ./spec/code_objects/namespace_object_spec.rb[1:1:1] | passed | 0.0002 seconds | ./spec/code_objects/namespace_object_spec.rb[1:1:2] | passed | 0.00019 seconds | ./spec/code_objects/namespace_object_spec.rb[1:2:1] | passed | 0.00038 seconds | ./spec/code_objects/namespace_object_spec.rb[1:2:2] | passed | 0.00057 seconds | ./spec/code_objects/namespace_object_spec.rb[1:3:1] | passed | 0.00038 seconds | ./spec/code_objects/namespace_object_spec.rb[1:3:2] | passed | 0.00038 seconds | ./spec/code_objects/namespace_object_spec.rb[1:4:1] | passed | 0.0003 seconds | ./spec/code_objects/namespace_object_spec.rb[1:5:1] | passed | 0.00027 seconds | ./spec/code_objects/namespace_object_spec.rb[1:6:1] | passed | 0.00408 seconds | ./spec/code_objects/namespace_object_spec.rb[1:6:2] | passed | 0.00455 seconds | ./spec/code_objects/namespace_object_spec.rb[1:6:3] | passed | 0.00443 seconds | ./spec/code_objects/namespace_object_spec.rb[1:6:4] | passed | 0.00374 seconds | ./spec/code_objects/namespace_object_spec.rb[1:7:1] | passed | 0.00286 seconds | ./spec/code_objects/proxy_spec.rb[1:1] | passed | 0.00019 seconds | ./spec/code_objects/proxy_spec.rb[1:2] | passed | 0.00033 seconds | ./spec/code_objects/proxy_spec.rb[1:3] | passed | 0.00031 seconds | ./spec/code_objects/proxy_spec.rb[1:4] | passed | 0.00027 seconds | ./spec/code_objects/proxy_spec.rb[1:5] | passed | 0.00037 seconds | ./spec/code_objects/proxy_spec.rb[1:6] | passed | 0.0002 seconds | ./spec/code_objects/proxy_spec.rb[1:7] | passed | 0.00017 seconds | ./spec/code_objects/proxy_spec.rb[1:8] | passed | 0.00015 seconds | ./spec/code_objects/proxy_spec.rb[1:9] | passed | 0.00086 seconds | ./spec/code_objects/proxy_spec.rb[1:10] | passed | 0.00068 seconds | ./spec/code_objects/proxy_spec.rb[1:11] | passed | 0.00032 seconds | ./spec/code_objects/proxy_spec.rb[1:12] | passed | 0.00176 seconds | ./spec/code_objects/proxy_spec.rb[1:13] | passed | 0.00025 seconds | ./spec/code_objects/proxy_spec.rb[1:14] | passed | 0.00036 seconds | ./spec/code_objects/proxy_spec.rb[1:15] | passed | 0.00022 seconds | ./spec/code_objects/proxy_spec.rb[1:16] | passed | 0.0009 seconds | ./spec/code_objects/proxy_spec.rb[1:17] | passed | 0.00143 seconds | ./spec/config_spec.rb[1:1:1] | passed | 0.0006 seconds | ./spec/config_spec.rb[1:1:2] | passed | 0.00051 seconds | ./spec/config_spec.rb[1:1:3] | passed | 0.00064 seconds | ./spec/config_spec.rb[1:1:4] | passed | 0.00033 seconds | ./spec/config_spec.rb[1:2:1] | passed | 0.00132 seconds | ./spec/config_spec.rb[1:3:1] | passed | 0.00033 seconds | ./spec/config_spec.rb[1:3:2] | passed | 0.0002 seconds | ./spec/config_spec.rb[1:3:3] | passed | 0.00027 seconds | ./spec/config_spec.rb[1:3:4] | passed | 0.00029 seconds | ./spec/config_spec.rb[1:3:5] | passed | 0.00034 seconds | ./spec/config_spec.rb[1:3:6] | passed | 0.00023 seconds | ./spec/config_spec.rb[1:3:7] | passed | 0.00027 seconds | ./spec/config_spec.rb[1:4:1] | passed | 0.00125 seconds | ./spec/config_spec.rb[1:4:2] | passed | 0.0004 seconds | ./spec/config_spec.rb[1:4:3] | passed | 0.00039 seconds | ./spec/config_spec.rb[1:4:4] | passed | 0.00098 seconds | ./spec/config_spec.rb[1:4:5] | passed | 0.00057 seconds | ./spec/config_spec.rb[1:4:6] | passed | 0.00088 seconds | ./spec/config_spec.rb[1:4:7] | passed | 0.00059 seconds | ./spec/core_ext/array_spec.rb[1:1:1] | passed | 0.00007 seconds | ./spec/core_ext/array_spec.rb[1:1:2] | passed | 0.00016 seconds | ./spec/core_ext/file_spec.rb[1:1:1] | passed | 0.00017 seconds | ./spec/core_ext/file_spec.rb[1:1:2] | passed | 0.00019 seconds | ./spec/core_ext/file_spec.rb[1:1:3] | passed | 0.00013 seconds | ./spec/core_ext/file_spec.rb[1:1:4] | passed | 0.00014 seconds | ./spec/core_ext/file_spec.rb[1:2:1] | passed | 0.00008 seconds | ./spec/core_ext/file_spec.rb[1:2:2] | passed | 0.00008 seconds | ./spec/core_ext/file_spec.rb[1:2:3] | passed | 0.0001 seconds | ./spec/core_ext/file_spec.rb[1:2:4] | passed | 0.0001 seconds | ./spec/core_ext/file_spec.rb[1:2:5] | passed | 0.00007 seconds | ./spec/core_ext/file_spec.rb[1:2:6] | passed | 0.00013 seconds | ./spec/core_ext/file_spec.rb[1:2:7] | passed | 0.00007 seconds | ./spec/core_ext/file_spec.rb[1:2:8] | passed | 0.00007 seconds | ./spec/core_ext/file_spec.rb[1:3:1] | passed | 0.00053 seconds | ./spec/core_ext/file_spec.rb[1:3:2] | passed | 0.00034 seconds | ./spec/core_ext/hash_spec.rb[1:1:1] | passed | 0.00009 seconds | ./spec/core_ext/hash_spec.rb[1:1:2] | passed | 0.00007 seconds | ./spec/core_ext/insertion_spec.rb[1:1:1] | passed | 0.00007 seconds | ./spec/core_ext/insertion_spec.rb[1:2:1] | passed | 0.00011 seconds | ./spec/core_ext/insertion_spec.rb[1:2:2] | passed | 0.00007 seconds | ./spec/core_ext/insertion_spec.rb[1:2:3] | passed | 0.00018 seconds | ./spec/core_ext/insertion_spec.rb[1:3:1] | passed | 0.00007 seconds | ./spec/core_ext/insertion_spec.rb[1:4:1] | passed | 0.0001 seconds | ./spec/core_ext/module_spec.rb[1:1:1] | passed | 0.00006 seconds | ./spec/core_ext/module_spec.rb[1:2:1] | passed | 0.00006 seconds | ./spec/core_ext/string_spec.rb[1:1:1] | passed | 0.00016 seconds | ./spec/core_ext/string_spec.rb[1:1:2] | passed | 0.00014 seconds | ./spec/core_ext/string_spec.rb[1:1:3] | passed | 0.00008 seconds | ./spec/core_ext/string_spec.rb[1:1:4] | passed | 0.00007 seconds | ./spec/core_ext/string_spec.rb[1:1:5] | passed | 0.00007 seconds | ./spec/core_ext/string_spec.rb[1:1:6] | passed | 0.00012 seconds | ./spec/core_ext/string_spec.rb[1:1:7] | passed | 0.00013 seconds | ./spec/core_ext/string_spec.rb[1:1:8] | passed | 0.00017 seconds | ./spec/core_ext/symbol_hash_spec.rb[1:1] | passed | 0.00008 seconds | ./spec/core_ext/symbol_hash_spec.rb[1:2:1] | passed | 0.00009 seconds | ./spec/core_ext/symbol_hash_spec.rb[1:3:1] | passed | 0.00009 seconds | ./spec/core_ext/symbol_hash_spec.rb[1:4] | passed | 0.00012 seconds | ./spec/core_ext/symbol_hash_spec.rb[1:5] | passed | 0.00006 seconds | ./spec/core_ext/symbol_hash_spec.rb[1:6] | passed | 0.00006 seconds | ./spec/core_ext/symbol_hash_spec.rb[1:7] | passed | 0.00006 seconds | ./spec/core_ext/symbol_hash_spec.rb[1:8] | passed | 0.00007 seconds | ./spec/core_ext/symbol_hash_spec.rb[1:9] | passed | 0.00008 seconds | ./spec/core_ext/symbol_hash_spec.rb[1:10] | passed | 0.00006 seconds | ./spec/docstring_parser_spec.rb[1:1:1] | passed | 0.00028 seconds | ./spec/docstring_parser_spec.rb[1:1:2] | passed | 0.00016 seconds | ./spec/docstring_parser_spec.rb[1:1:3] | passed | 0.00016 seconds | ./spec/docstring_parser_spec.rb[1:1:4] | passed | 0.00015 seconds | ./spec/docstring_parser_spec.rb[1:1:5] | passed | 0.00034 seconds | ./spec/docstring_parser_spec.rb[1:1:6] | passed | 0.00011 seconds | ./spec/docstring_parser_spec.rb[1:1:7] | passed | 0.00056 seconds | ./spec/docstring_parser_spec.rb[1:1:8] | passed | 0.0001 seconds | ./spec/docstring_parser_spec.rb[1:2:1] | passed | 0.0006 seconds | ./spec/docstring_parser_spec.rb[1:2:2] | passed | 0.00013 seconds | ./spec/docstring_parser_spec.rb[1:2:3] | passed | 0.00021 seconds | ./spec/docstring_parser_spec.rb[1:2:4] | passed | 0.00053 seconds | ./spec/docstring_parser_spec.rb[1:2:5] | passed | 0.00018 seconds | ./spec/docstring_parser_spec.rb[1:2:6] | passed | 0.00012 seconds | ./spec/docstring_parser_spec.rb[1:2:7] | passed | 0.00015 seconds | ./spec/docstring_parser_spec.rb[1:2:8] | passed | 0.00015 seconds | ./spec/docstring_parser_spec.rb[1:2:9] | passed | 0.00011 seconds | ./spec/docstring_parser_spec.rb[1:2:10] | passed | 0.00012 seconds | ./spec/docstring_parser_spec.rb[1:2:11] | passed | 0.00015 seconds | ./spec/docstring_parser_spec.rb[1:2:12] | passed | 0.00014 seconds | ./spec/docstring_parser_spec.rb[1:3:1] | passed | 0.00011 seconds | ./spec/docstring_parser_spec.rb[1:4:1] | passed | 0.00013 seconds | ./spec/docstring_parser_spec.rb[1:5:1] | passed | 0.0001 seconds | ./spec/docstring_parser_spec.rb[1:6:1] | passed | 0.00014 seconds | ./spec/docstring_parser_spec.rb[1:7:1] | passed | 0.00009 seconds | ./spec/docstring_parser_spec.rb[1:8:1] | passed | 0.00011 seconds | ./spec/docstring_parser_spec.rb[1:8:2] | passed | 0.00086 seconds | ./spec/docstring_parser_spec.rb[1:8:3] | passed | 0.00149 seconds | ./spec/docstring_parser_spec.rb[1:8:4] | passed | 0.001 seconds | ./spec/docstring_parser_spec.rb[1:8:5] | passed | 0.00118 seconds | ./spec/docstring_parser_spec.rb[1:9:1] | passed | 0.0008 seconds | ./spec/docstring_parser_spec.rb[1:9:2] | passed | 0.00067 seconds | ./spec/docstring_parser_spec.rb[1:9:3] | passed | 0.00068 seconds | ./spec/docstring_spec.rb[1:1:1] | passed | 0.0001 seconds | ./spec/docstring_spec.rb[1:2:1] | passed | 0.00015 seconds | ./spec/docstring_spec.rb[1:2:2] | passed | 0.00043 seconds | ./spec/docstring_spec.rb[1:2:3] | passed | 0.0001 seconds | ./spec/docstring_spec.rb[1:3:1] | passed | 0.00013 seconds | ./spec/docstring_spec.rb[1:3:2] | passed | 0.00037 seconds | ./spec/docstring_spec.rb[1:4:1] | passed | 0.00037 seconds | ./spec/docstring_spec.rb[1:4:2] | passed | 0.00023 seconds | ./spec/docstring_spec.rb[1:4:3] | passed | 0.00019 seconds | ./spec/docstring_spec.rb[1:4:4] | passed | 0.00014 seconds | ./spec/docstring_spec.rb[1:4:5] | passed | 0.00017 seconds | ./spec/docstring_spec.rb[1:4:6] | passed | 0.00023 seconds | ./spec/docstring_spec.rb[1:4:7] | passed | 0.00021 seconds | ./spec/docstring_spec.rb[1:4:8] | passed | 0.00064 seconds | ./spec/docstring_spec.rb[1:4:9] | passed | 0.00015 seconds | ./spec/docstring_spec.rb[1:4:10] | passed | 0.00014 seconds | ./spec/docstring_spec.rb[1:4:11] | passed | 0.00016 seconds | ./spec/docstring_spec.rb[1:4:12] | passed | 0.00026 seconds | ./spec/docstring_spec.rb[1:5:1] | passed | 0.00179 seconds | ./spec/docstring_spec.rb[1:5:2] | passed | 0.0007 seconds | ./spec/docstring_spec.rb[1:5:3] | passed | 0.0002 seconds | ./spec/docstring_spec.rb[1:5:4] | passed | 0.00033 seconds | ./spec/docstring_spec.rb[1:5:5] | passed | 0.00037 seconds | ./spec/docstring_spec.rb[1:5:6] | passed | 0.0008 seconds | ./spec/docstring_spec.rb[1:5:7] | passed | 0.00049 seconds | ./spec/docstring_spec.rb[1:5:8] | passed | 0.00177 seconds | ./spec/docstring_spec.rb[1:5:9] | passed | 0.00094 seconds | ./spec/docstring_spec.rb[1:6:1] | passed | 0.00018 seconds | ./spec/docstring_spec.rb[1:6:2] | passed | 0.00012 seconds | ./spec/docstring_spec.rb[1:6:3] | passed | 0.00032 seconds | ./spec/docstring_spec.rb[1:6:4] | passed | 0.00041 seconds | ./spec/docstring_spec.rb[1:6:5] | passed | 0.00013 seconds | ./spec/docstring_spec.rb[1:6:6] | passed | 0.00012 seconds | ./spec/docstring_spec.rb[1:7:1] | passed | 0.00022 seconds | ./spec/docstring_spec.rb[1:8:1] | passed | 0.00021 seconds | ./spec/docstring_spec.rb[1:9:1] | passed | 0.00024 seconds | ./spec/docstring_spec.rb[1:9:2] | passed | 0.00028 seconds | ./spec/docstring_spec.rb[1:9:3] | passed | 0.00027 seconds | ./spec/docstring_spec.rb[1:9:4] | passed | 0.00019 seconds | ./spec/docstring_spec.rb[1:9:5] | passed | 0.00017 seconds | ./spec/docstring_spec.rb[1:9:6] | passed | 0.0002 seconds | ./spec/docstring_spec.rb[1:9:7] | passed | 0.00015 seconds | ./spec/docstring_spec.rb[1:10:1] | passed | 0.00016 seconds | ./spec/docstring_spec.rb[1:10:2] | passed | 0.00017 seconds | ./spec/docstring_spec.rb[1:10:3] | passed | 0.0002 seconds | ./spec/docstring_spec.rb[1:10:4] | passed | 0.00017 seconds | ./spec/docstring_spec.rb[1:10:5] | passed | 0.00012 seconds | ./spec/docstring_spec.rb[1:11:1] | passed | 0.00225 seconds | ./spec/handlers/alias_handler_spec.rb[1:1] | passed | 0.00031 seconds | ./spec/handlers/alias_handler_spec.rb[1:2] | passed | 0.00024 seconds | ./spec/handlers/alias_handler_spec.rb[1:3] | passed | 0.00009 seconds | ./spec/handlers/alias_handler_spec.rb[1:4] | passed | 0.00012 seconds | ./spec/handlers/alias_handler_spec.rb[1:5] | passed | 0.00014 seconds | ./spec/handlers/alias_handler_spec.rb[1:6] | passed | 0.00015 seconds | ./spec/handlers/alias_handler_spec.rb[1:7] | passed | 0.00008 seconds | ./spec/handlers/alias_handler_spec.rb[1:8] | passed | 0.00014 seconds | ./spec/handlers/alias_handler_spec.rb[1:9] | passed | 0.0001 seconds | ./spec/handlers/alias_handler_spec.rb[1:10] | passed | 0.00017 seconds | ./spec/handlers/alias_handler_spec.rb[1:11] | passed | 0.00007 seconds | ./spec/handlers/alias_handler_spec.rb[1:12] | passed | 0.00007 seconds | ./spec/handlers/alias_handler_spec.rb[1:13] | passed | 0.00007 seconds | ./spec/handlers/alias_handler_spec.rb[1:14] | passed | 0.00013 seconds | ./spec/handlers/alias_handler_spec.rb[1:15] | passed | 0.00007 seconds | ./spec/handlers/alias_handler_spec.rb[1:16] | passed | 0.00007 seconds | ./spec/handlers/alias_handler_spec.rb[1:17] | passed | 0.0001 seconds | ./spec/handlers/alias_handler_spec.rb[1:18] | passed | 0.00008 seconds | ./spec/handlers/alias_handler_spec.rb[1:19] | passed | 0.00015 seconds | ./spec/handlers/alias_handler_spec.rb[1:20] | passed | 0.00007 seconds | ./spec/handlers/alias_handler_spec.rb[1:21] | passed | 0.0001 seconds | ./spec/handlers/alias_handler_spec.rb[1:22] | passed | 0.00149 seconds | ./spec/handlers/alias_handler_spec.rb[1:23] | passed | 0.00084 seconds | ./spec/handlers/attribute_handler_spec.rb[1:1] | passed | 0.00011 seconds | ./spec/handlers/attribute_handler_spec.rb[1:2] | passed | 0.00015 seconds | ./spec/handlers/attribute_handler_spec.rb[1:3] | passed | 0.00008 seconds | ./spec/handlers/attribute_handler_spec.rb[1:4] | passed | 0.0001 seconds | ./spec/handlers/attribute_handler_spec.rb[1:5] | passed | 0.00009 seconds | ./spec/handlers/attribute_handler_spec.rb[1:6] | passed | 0.00015 seconds | ./spec/handlers/attribute_handler_spec.rb[1:7] | passed | 0.00009 seconds | ./spec/handlers/attribute_handler_spec.rb[1:8] | passed | 0.00008 seconds | ./spec/handlers/attribute_handler_spec.rb[1:9] | passed | 0.0001 seconds | ./spec/handlers/attribute_handler_spec.rb[1:10] | passed | 0.00011 seconds | ./spec/handlers/attribute_handler_spec.rb[1:11] | passed | 0.00029 seconds | ./spec/handlers/attribute_handler_spec.rb[1:12] | passed | 0.00027 seconds | ./spec/handlers/attribute_handler_spec.rb[1:13] | passed | 0.00008 seconds | ./spec/handlers/attribute_handler_spec.rb[1:14] | passed | 0.00012 seconds | ./spec/handlers/attribute_handler_spec.rb[1:15] | passed | 0.00007 seconds | ./spec/handlers/base_spec.rb[1:1:1] | passed | 0.00097 seconds | ./spec/handlers/base_spec.rb[1:1:2] | passed | 0.00031 seconds | ./spec/handlers/base_spec.rb[1:1:3] | passed | 0.0003 seconds | ./spec/handlers/base_spec.rb[1:1:4] | passed | 0.0003 seconds | ./spec/handlers/base_spec.rb[1:2:1] | passed | 0.00017 seconds | ./spec/handlers/base_spec.rb[1:3:1] | passed | 0.00163 seconds | ./spec/handlers/base_spec.rb[1:4:1] | passed | 0.00164 seconds | ./spec/handlers/base_spec.rb[1:5:1] | passed | 0.0002 seconds | ./spec/handlers/base_spec.rb[1:5:2] | passed | 0.00024 seconds | ./spec/handlers/base_spec.rb[1:5:3] | passed | 0.00013 seconds | ./spec/handlers/base_spec.rb[1:6:1:1] | passed | 0.00097 seconds | ./spec/handlers/base_spec.rb[1:6:1:2] | passed | 0.00074 seconds | ./spec/handlers/base_spec.rb[1:6:1:3] | passed | 0.00084 seconds | ./spec/handlers/base_spec.rb[1:6:1:4] | passed | 0.00077 seconds | ./spec/handlers/base_spec.rb[1:6:1:5] | passed | 0.0021 seconds | ./spec/handlers/base_spec.rb[1:6:1:6] | passed | 0.00243 seconds | ./spec/handlers/base_spec.rb[1:6:2:1] | passed | 0.02453 seconds | ./spec/handlers/base_spec.rb[1:6:2:2] | passed | 0.00187 seconds | ./spec/handlers/base_spec.rb[1:6:2:3] | passed | 0.00128 seconds | ./spec/handlers/base_spec.rb[1:6:2:4] | passed | 0.00118 seconds | ./spec/handlers/base_spec.rb[1:6:2:5] | passed | 0.00493 seconds | ./spec/handlers/base_spec.rb[1:6:2:6] | passed | 0.0035 seconds | ./spec/handlers/c/alias_handler_spec.rb[1:1] | passed | 0.00554 seconds | ./spec/handlers/c/alias_handler_spec.rb[1:2] | passed | 0.00141 seconds | ./spec/handlers/c/attribute_handler_spec.rb[1:1] | passed | 0.00138 seconds | ./spec/handlers/c/attribute_handler_spec.rb[1:2] | passed | 0.00136 seconds | ./spec/handlers/c/attribute_handler_spec.rb[1:3] | passed | 0.00128 seconds | ./spec/handlers/c/attribute_handler_spec.rb[1:4] | passed | 0.00132 seconds | ./spec/handlers/c/class_handler_spec.rb[1:1] | passed | 0.00065 seconds | ./spec/handlers/c/class_handler_spec.rb[1:2] | passed | 0.00143 seconds | ./spec/handlers/c/class_handler_spec.rb[1:3] | passed | 0.00094 seconds | ./spec/handlers/c/class_handler_spec.rb[1:4] | passed | 0.00107 seconds | ./spec/handlers/c/class_handler_spec.rb[1:5] | passed | 0.00088 seconds | ./spec/handlers/c/class_handler_spec.rb[1:6] | passed | 0.00078 seconds | ./spec/handlers/c/class_handler_spec.rb[1:7] | passed | 0.00067 seconds | ./spec/handlers/c/class_handler_spec.rb[1:8] | passed | 0.00108 seconds | ./spec/handlers/c/class_handler_spec.rb[1:9] | passed | 0.00171 seconds | ./spec/handlers/c/constant_handler_spec.rb[1:1] | passed | 0.00089 seconds | ./spec/handlers/c/constant_handler_spec.rb[1:2] | passed | 0.00122 seconds | ./spec/handlers/c/constant_handler_spec.rb[1:3] | passed | 0.0009 seconds | ./spec/handlers/c/constant_handler_spec.rb[1:4] | passed | 0.00105 seconds | ./spec/handlers/c/constant_handler_spec.rb[1:5] | passed | 0.00148 seconds | ./spec/handlers/c/init_handler_spec.rb[1:1] | passed | 0.00094 seconds | ./spec/handlers/c/init_handler_spec.rb[1:2] | passed | 0.00058 seconds | ./spec/handlers/c/init_handler_spec.rb[1:3] | passed | 0.00107 seconds | ./spec/handlers/c/init_handler_spec.rb[1:4] | passed | 0.00091 seconds | ./spec/handlers/c/method_handler_spec.rb[1:1] | passed | 0.00093 seconds | ./spec/handlers/c/method_handler_spec.rb[1:2] | passed | 0.00087 seconds | ./spec/handlers/c/method_handler_spec.rb[1:3] | passed | 0.00076 seconds | ./spec/handlers/c/method_handler_spec.rb[1:4] | passed | 0.00135 seconds | ./spec/handlers/c/method_handler_spec.rb[1:5] | passed | 0.00065 seconds | ./spec/handlers/c/method_handler_spec.rb[1:6] | passed | 0.0013 seconds | ./spec/handlers/c/method_handler_spec.rb[1:7] | passed | 0.00128 seconds | ./spec/handlers/c/method_handler_spec.rb[1:8] | passed | 0.00175 seconds | ./spec/handlers/c/method_handler_spec.rb[1:9] | passed | 0.00166 seconds | ./spec/handlers/c/method_handler_spec.rb[1:10] | passed | 0.00241 seconds | ./spec/handlers/c/method_handler_spec.rb[1:11] | passed | 0.00101 seconds | ./spec/handlers/c/method_handler_spec.rb[1:12] | passed | 0.00194 seconds | ./spec/handlers/c/method_handler_spec.rb[1:13] | passed | 0.00226 seconds | ./spec/handlers/c/method_handler_spec.rb[1:14] | passed | 0.0013 seconds | ./spec/handlers/c/method_handler_spec.rb[1:15] | passed | 0.00119 seconds | ./spec/handlers/c/method_handler_spec.rb[1:16] | passed | 0.00719 seconds | ./spec/handlers/c/method_handler_spec.rb[1:17] | passed | 0.00163 seconds | ./spec/handlers/c/method_handler_spec.rb[1:18] | passed | 0.00204 seconds | ./spec/handlers/c/method_handler_spec.rb[1:19] | passed | 0.00406 seconds | ./spec/handlers/c/method_handler_spec.rb[1:20] | passed | 0.0016 seconds | ./spec/handlers/c/mixin_handler_spec.rb[1:1] | passed | 0.00166 seconds | ./spec/handlers/c/mixin_handler_spec.rb[1:2] | passed | 0.00111 seconds | ./spec/handlers/c/mixin_handler_spec.rb[1:3] | passed | 0.00122 seconds | ./spec/handlers/c/module_handler_spec.rb[1:1] | passed | 0.00053 seconds | ./spec/handlers/c/module_handler_spec.rb[1:2] | passed | 0.00089 seconds | ./spec/handlers/c/module_handler_spec.rb[1:3] | passed | 0.00088 seconds | ./spec/handlers/c/module_handler_spec.rb[1:4] | passed | 0.00072 seconds | ./spec/handlers/c/module_handler_spec.rb[1:5] | passed | 0.00066 seconds | ./spec/handlers/c/module_handler_spec.rb[1:6] | passed | 0.00131 seconds | ./spec/handlers/c/module_handler_spec.rb[1:7] | passed | 0.00073 seconds | ./spec/handlers/c/module_handler_spec.rb[1:8] | passed | 0.00065 seconds | ./spec/handlers/c/override_comment_handler_spec.rb[1:1] | passed | 0.00082 seconds | ./spec/handlers/c/override_comment_handler_spec.rb[1:2] | passed | 0.00075 seconds | ./spec/handlers/c/override_comment_handler_spec.rb[1:3] | passed | 0.00159 seconds | ./spec/handlers/c/override_comment_handler_spec.rb[1:4] | passed | 0.0008 seconds | ./spec/handlers/c/path_handler_spec.rb[1:1] | passed | 0.00134 seconds | ./spec/handlers/c/path_handler_spec.rb[1:2] | passed | 0.00144 seconds | ./spec/handlers/c/path_handler_spec.rb[1:3] | passed | 0.00206 seconds | ./spec/handlers/c/struct_handler_spec.rb[1:1] | passed | 0.00112 seconds | ./spec/handlers/class_condition_handler_spec.rb[1:1] | passed | 0.00013 seconds | ./spec/handlers/class_condition_handler_spec.rb[1:2] | passed | 0.00011 seconds | ./spec/handlers/class_condition_handler_spec.rb[1:3] | passed | 0.00007 seconds | ./spec/handlers/class_condition_handler_spec.rb[1:4] | passed | 0.00016 seconds | ./spec/handlers/class_condition_handler_spec.rb[1:5] | passed | 0.00028 seconds | ./spec/handlers/class_condition_handler_spec.rb[1:6] | passed | 0.00019 seconds | ./spec/handlers/class_condition_handler_spec.rb[1:7] | passed | 0.00014 seconds | ./spec/handlers/class_condition_handler_spec.rb[1:8] | passed | 0.00008 seconds | ./spec/handlers/class_condition_handler_spec.rb[1:9] | passed | 0.00008 seconds | ./spec/handlers/class_condition_handler_spec.rb[1:10] | passed | 0.00011 seconds | ./spec/handlers/class_condition_handler_spec.rb[1:11] | passed | 0.0023 seconds | ./spec/handlers/class_handler_spec.rb[1:1] | passed | 0.00013 seconds | ./spec/handlers/class_handler_spec.rb[1:2] | passed | 0.00008 seconds | ./spec/handlers/class_handler_spec.rb[1:3] | passed | 0.00019 seconds | ./spec/handlers/class_handler_spec.rb[1:4] | passed | 0.00008 seconds | ./spec/handlers/class_handler_spec.rb[1:5] | passed | 0.00013 seconds | ./spec/handlers/class_handler_spec.rb[1:6] | passed | 0.00008 seconds | ./spec/handlers/class_handler_spec.rb[1:7] | passed | 0.00009 seconds | ./spec/handlers/class_handler_spec.rb[1:8] | passed | 0.00013 seconds | ./spec/handlers/class_handler_spec.rb[1:9] | passed | 0.00007 seconds | ./spec/handlers/class_handler_spec.rb[1:10] | passed | 0.00045 seconds | ./spec/handlers/class_handler_spec.rb[1:11] | passed | 0.00031 seconds | ./spec/handlers/class_handler_spec.rb[1:12] | passed | 0.00016 seconds | ./spec/handlers/class_handler_spec.rb[1:13] | passed | 0.00023 seconds | ./spec/handlers/class_handler_spec.rb[1:14] | passed | 0.00135 seconds | ./spec/handlers/class_handler_spec.rb[1:15] | passed | 0.00086 seconds | ./spec/handlers/class_handler_spec.rb[1:16] | passed | 0.00095 seconds | ./spec/handlers/class_handler_spec.rb[1:17] | passed | 0.00084 seconds | ./spec/handlers/class_handler_spec.rb[1:18] | passed | 0.00139 seconds | ./spec/handlers/class_handler_spec.rb[1:19] | passed | 0.0012 seconds | ./spec/handlers/class_handler_spec.rb[1:20] | passed | 0.00153 seconds | ./spec/handlers/class_handler_spec.rb[1:21] | passed | 0.00124 seconds | ./spec/handlers/class_handler_spec.rb[1:22] | passed | 0.00142 seconds | ./spec/handlers/class_handler_spec.rb[1:23] | passed | 0.0013 seconds | ./spec/handlers/class_handler_spec.rb[1:24] | passed | 0.00153 seconds | ./spec/handlers/class_handler_spec.rb[1:25] | passed | 0.00007 seconds | ./spec/handlers/class_handler_spec.rb[1:26] | passed | 0.0001 seconds | ./spec/handlers/class_handler_spec.rb[1:27] | passed | 0.00069 seconds | ./spec/handlers/class_handler_spec.rb[1:28] | passed | 0.00048 seconds | ./spec/handlers/class_handler_spec.rb[1:29] | passed | 0.00007 seconds | ./spec/handlers/class_handler_spec.rb[1:30] | passed | 0.00042 seconds | ./spec/handlers/class_handler_spec.rb[1:31] | passed | 0.00034 seconds | ./spec/handlers/class_handler_spec.rb[1:32] | passed | 0.00007 seconds | ./spec/handlers/class_handler_spec.rb[1:33] | passed | 0.00036 seconds | ./spec/handlers/class_handler_spec.rb[1:34] | passed | 0.0001 seconds | ./spec/handlers/class_handler_spec.rb[1:35] | passed | 0.00009 seconds | ./spec/handlers/class_handler_spec.rb[1:36] | passed | 0.00011 seconds | ./spec/handlers/class_handler_spec.rb[1:37] | passed | 0.00008 seconds | ./spec/handlers/class_handler_spec.rb[1:38:1] | passed | 0.0001 seconds | ./spec/handlers/class_handler_spec.rb[1:38:2] | passed | 0.00007 seconds | ./spec/handlers/class_handler_spec.rb[1:38:3] | passed | 0.00014 seconds | ./spec/handlers/class_handler_spec.rb[1:38:4] | passed | 0.00008 seconds | ./spec/handlers/class_handler_spec.rb[1:38:5] | passed | 0.0001 seconds | ./spec/handlers/class_handler_spec.rb[1:38:6] | passed | 0.00009 seconds | ./spec/handlers/class_handler_spec.rb[1:38:7] | passed | 0.00007 seconds | ./spec/handlers/class_handler_spec.rb[1:38:8] | passed | 0.00006 seconds | ./spec/handlers/class_handler_spec.rb[1:38:9] | passed | 0.00006 seconds | ./spec/handlers/class_handler_spec.rb[1:38:10] | passed | 0.00012 seconds | ./spec/handlers/class_handler_spec.rb[1:39:1] | passed | 0.00009 seconds | ./spec/handlers/class_handler_spec.rb[1:39:2] | passed | 0.00006 seconds | ./spec/handlers/class_handler_spec.rb[1:39:3] | passed | 0.0001 seconds | ./spec/handlers/class_handler_spec.rb[1:39:4] | passed | 0.00007 seconds | ./spec/handlers/class_handler_spec.rb[1:39:5] | passed | 0.00006 seconds | ./spec/handlers/class_handler_spec.rb[1:39:6] | passed | 0.0001 seconds | ./spec/handlers/class_handler_spec.rb[1:39:7] | passed | 0.00006 seconds | ./spec/handlers/class_handler_spec.rb[1:39:8] | passed | 0.00006 seconds | ./spec/handlers/class_handler_spec.rb[1:39:9] | passed | 0.00006 seconds | ./spec/handlers/class_handler_spec.rb[1:39:10] | passed | 0.00006 seconds | ./spec/handlers/class_handler_spec.rb[1:40] | passed | 0.00026 seconds | ./spec/handlers/class_handler_spec.rb[1:41] | passed | 0.00007 seconds | ./spec/handlers/class_variable_handler_spec.rb[1:1] | passed | 0.00007 seconds | ./spec/handlers/constant_handler_spec.rb[1:1] | passed | 0.00011 seconds | ./spec/handlers/constant_handler_spec.rb[1:2] | passed | 0.00007 seconds | ./spec/handlers/constant_handler_spec.rb[1:3] | passed | 0.00011 seconds | ./spec/handlers/constant_handler_spec.rb[1:4] | passed | 0.00034 seconds | ./spec/handlers/constant_handler_spec.rb[1:5] | passed | 0.00103 seconds | ./spec/handlers/constant_handler_spec.rb[1:6] | passed | 0.00027 seconds | ./spec/handlers/constant_handler_spec.rb[1:7] | passed | 0.00012 seconds | ./spec/handlers/constant_handler_spec.rb[1:8] | passed | 0.00018 seconds | ./spec/handlers/constant_handler_spec.rb[1:9] | passed | 0.00049 seconds | ./spec/handlers/constant_handler_spec.rb[1:10] | passed | 0.0008 seconds | ./spec/handlers/constant_handler_spec.rb[1:11] | passed | 0.00077 seconds | ./spec/handlers/constant_handler_spec.rb[1:12] | passed | 0.00139 seconds | ./spec/handlers/constant_handler_spec.rb[1:13] | passed | 0.0018 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:1] | passed | 0.00197 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:2:1] | passed | 0.00115 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:3:1] | passed | 0.00087 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:4] | passed | 0.00126 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:5:1] | passed | 0.0015 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:6:1:1] | passed | 0.00161 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:6:2:1:1] | passed | 0.00248 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:6:2:2:1] | passed | 0.00287 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:6:2:3:1] | passed | 0.00256 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:6:2:4:1] | passed | 0.00247 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:6:3:1] | passed | 0.00149 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:7:1:1] | passed | 0.00126 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:7:2:1:1:1] | passed | 0.00154 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:7:2:1:2:1] | passed | 0.00159 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:7:2:1:3:1] | passed | 0.00248 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:7:2:2:1:1] | passed | 0.00173 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:7:2:2:2:1] | passed | 0.00156 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:7:2:2:3:1] | passed | 0.00289 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:8:1] | passed | 0.00133 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:8:2:1:1] | passed | 0.00678 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:8:2:2:1] | passed | 0.00146 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:9:1] | passed | 0.00183 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:9:2:1] | passed | 0.00163 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:9:2:2:1] | passed | 0.00166 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:9:3:1] | passed | 0.00206 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:9:4] | passed | 0.00173 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:9:5:1] | passed | 0.00197 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:9:5:2:1] | passed | 0.00155 seconds | ./spec/handlers/decorator_handler_methods_spec.rb[1:1:9:6:1] | passed | 0.0016 seconds | ./spec/handlers/dsl_handler_spec.rb[1:1] | passed | 0.00023 seconds | ./spec/handlers/dsl_handler_spec.rb[1:2] | passed | 0.00014 seconds | ./spec/handlers/dsl_handler_spec.rb[1:3] | passed | 0.00011 seconds | ./spec/handlers/dsl_handler_spec.rb[1:4] | passed | 0.00011 seconds | ./spec/handlers/dsl_handler_spec.rb[1:5] | passed | 0.00013 seconds | ./spec/handlers/dsl_handler_spec.rb[1:6] | passed | 0.0001 seconds | ./spec/handlers/dsl_handler_spec.rb[1:7] | passed | 0.00007 seconds | ./spec/handlers/dsl_handler_spec.rb[1:8] | passed | 0.00008 seconds | ./spec/handlers/dsl_handler_spec.rb[1:9] | passed | 0.00008 seconds | ./spec/handlers/dsl_handler_spec.rb[1:10] | passed | 0.00006 seconds | ./spec/handlers/dsl_handler_spec.rb[1:11] | passed | 0.00007 seconds | ./spec/handlers/dsl_handler_spec.rb[1:12] | passed | 0.00007 seconds | ./spec/handlers/dsl_handler_spec.rb[1:13] | passed | 0.00007 seconds | ./spec/handlers/dsl_handler_spec.rb[1:14] | passed | 0.00007 seconds | ./spec/handlers/dsl_handler_spec.rb[1:15] | passed | 0.0001 seconds | ./spec/handlers/dsl_handler_spec.rb[1:16] | passed | 0.00007 seconds | ./spec/handlers/dsl_handler_spec.rb[1:17] | passed | 0.00006 seconds | ./spec/handlers/dsl_handler_spec.rb[1:18] | passed | 0.0001 seconds | ./spec/handlers/dsl_handler_spec.rb[1:19] | passed | 0.00009 seconds | ./spec/handlers/dsl_handler_spec.rb[1:20] | passed | 0.00007 seconds | ./spec/handlers/dsl_handler_spec.rb[1:21] | passed | 0.00025 seconds | ./spec/handlers/dsl_handler_spec.rb[1:22] | passed | 0.00017 seconds | ./spec/handlers/dsl_handler_spec.rb[1:23] | passed | 0.00014 seconds | ./spec/handlers/dsl_handler_spec.rb[1:24] | passed | 0.0001 seconds | ./spec/handlers/dsl_handler_spec.rb[1:25] | passed | 0.00011 seconds | ./spec/handlers/dsl_handler_spec.rb[1:26] | passed | 0.00007 seconds | ./spec/handlers/dsl_handler_spec.rb[1:27] | passed | 0.00007 seconds | ./spec/handlers/dsl_handler_spec.rb[1:28] | passed | 0.00082 seconds | ./spec/handlers/dsl_handler_spec.rb[1:29] | passed | 0.00061 seconds | ./spec/handlers/dsl_handler_spec.rb[1:30] | passed | 0.00017 seconds | ./spec/handlers/dsl_handler_spec.rb[1:31] | passed | 0.00007 seconds | ./spec/handlers/dsl_handler_spec.rb[1:32] | passed | 0.00023 seconds | ./spec/handlers/exception_handler_spec.rb[1:1] | passed | 0.00015 seconds | ./spec/handlers/exception_handler_spec.rb[1:2] | passed | 0.00009 seconds | ./spec/handlers/exception_handler_spec.rb[1:3] | passed | 0.00016 seconds | ./spec/handlers/exception_handler_spec.rb[1:4] | passed | 0.0001 seconds | ./spec/handlers/exception_handler_spec.rb[1:5] | passed | 0.00009 seconds | ./spec/handlers/exception_handler_spec.rb[1:6] | passed | 0.00011 seconds | ./spec/handlers/exception_handler_spec.rb[1:7] | passed | 0.00009 seconds | ./spec/handlers/exception_handler_spec.rb[1:8] | passed | 0.00011 seconds | ./spec/handlers/exception_handler_spec.rb[1:9] | passed | 0.0001 seconds | ./spec/handlers/exception_handler_spec.rb[1:10] | passed | 0.00009 seconds | ./spec/handlers/extend_handler_spec.rb[1:1] | passed | 0.00018 seconds | ./spec/handlers/extend_handler_spec.rb[1:2] | passed | 0.00011 seconds | ./spec/handlers/extend_handler_spec.rb[1:3] | passed | 0.00013 seconds | ./spec/handlers/extend_handler_spec.rb[1:4] | passed | 0.00069 seconds | ./spec/handlers/legacy_base_spec.rb[1:1] | passed | 0.00073 seconds | ./spec/handlers/legacy_base_spec.rb[1:2] | passed | 0.00044 seconds | ./spec/handlers/legacy_base_spec.rb[1:3] | passed | 0.00046 seconds | ./spec/handlers/legacy_base_spec.rb[1:4] | passed | 0.00078 seconds | ./spec/handlers/legacy_base_spec.rb[1:5] | passed | 0.0008 seconds | ./spec/handlers/legacy_base_spec.rb[1:6] | passed | 0.00083 seconds | ./spec/handlers/legacy_base_spec.rb[1:7] | passed | 0.00107 seconds | ./spec/handlers/legacy_base_spec.rb[1:8] | passed | 0.00056 seconds | ./spec/handlers/legacy_base_spec.rb[1:9] | passed | 0.00035 seconds | ./spec/handlers/legacy_base_spec.rb[1:10] | passed | 0.00066 seconds | ./spec/handlers/legacy_base_spec.rb[1:11] | passed | 0.00042 seconds | ./spec/handlers/legacy_base_spec.rb[2:1] | passed | 0.00118 seconds | ./spec/handlers/legacy_base_spec.rb[2:2] | passed | 0.00177 seconds | ./spec/handlers/legacy_base_spec.rb[2:3] | passed | 0.00053 seconds | ./spec/handlers/legacy_base_spec.rb[2:4] | passed | 0.00047 seconds | ./spec/handlers/legacy_base_spec.rb[2:5] | passed | 0.00047 seconds | ./spec/handlers/legacy_base_spec.rb[2:6] | passed | 0.0005 seconds | ./spec/handlers/legacy_base_spec.rb[2:7] | passed | 0.0023 seconds | ./spec/handlers/legacy_base_spec.rb[2:8] | passed | 0.00083 seconds | ./spec/handlers/legacy_base_spec.rb[2:9] | passed | 0.00047 seconds | ./spec/handlers/legacy_base_spec.rb[2:10] | passed | 0.00544 seconds | ./spec/handlers/legacy_base_spec.rb[2:11] | passed | 0.00044 seconds | ./spec/handlers/method_condition_handler_spec.rb[1:1] | passed | 0.00007 seconds | ./spec/handlers/method_condition_handler_spec.rb[1:2] | passed | 0.00012 seconds | ./spec/handlers/method_handler_spec.rb[1:1] | passed | 0.00033 seconds | ./spec/handlers/method_handler_spec.rb[1:2] | passed | 0.00029 seconds | ./spec/handlers/method_handler_spec.rb[1:3] | passed | 0.00013 seconds | ./spec/handlers/method_handler_spec.rb[1:4] | passed | 0.0001 seconds | ./spec/handlers/method_handler_spec.rb[1:5] | passed | 0.00007 seconds | ./spec/handlers/method_handler_spec.rb[1:6] | passed | 0.00007 seconds | ./spec/handlers/method_handler_spec.rb[1:7] | passed | 0.00009 seconds | ./spec/handlers/method_handler_spec.rb[1:8] | passed | 0.00007 seconds | ./spec/handlers/method_handler_spec.rb[1:9] | passed | 0.00007 seconds | ./spec/handlers/method_handler_spec.rb[1:10] | passed | 0.00009 seconds | ./spec/handlers/method_handler_spec.rb[1:11] | passed | 0.00007 seconds | ./spec/handlers/method_handler_spec.rb[1:12] | passed | 0.00007 seconds | ./spec/handlers/method_handler_spec.rb[1:13] | passed | 0.0001 seconds | ./spec/handlers/method_handler_spec.rb[1:14] | passed | 0.00007 seconds | ./spec/handlers/method_handler_spec.rb[1:15] | passed | 0.00007 seconds | ./spec/handlers/method_handler_spec.rb[1:16] | passed | 0.00009 seconds | ./spec/handlers/method_handler_spec.rb[1:17] | passed | 0.00006 seconds | ./spec/handlers/method_handler_spec.rb[1:18] | passed | 0.00006 seconds | ./spec/handlers/method_handler_spec.rb[1:19] | passed | 0.00006 seconds | ./spec/handlers/method_handler_spec.rb[1:20] | passed | 0.00007 seconds | ./spec/handlers/method_handler_spec.rb[1:21] | passed | 0.00006 seconds | ./spec/handlers/method_handler_spec.rb[1:22] | passed | 0.00013 seconds | ./spec/handlers/method_handler_spec.rb[1:23] | passed | 0.00006 seconds | ./spec/handlers/method_handler_spec.rb[1:24] | passed | 0.00006 seconds | ./spec/handlers/method_handler_spec.rb[1:25] | passed | 0.00011 seconds | ./spec/handlers/method_handler_spec.rb[1:26] | passed | 0.00018 seconds | ./spec/handlers/method_handler_spec.rb[1:27] | passed | 0.00027 seconds | ./spec/handlers/method_handler_spec.rb[1:28] | passed | 0.00012 seconds | ./spec/handlers/method_handler_spec.rb[1:29] | passed | 0.00017 seconds | ./spec/handlers/method_handler_spec.rb[1:30] | passed | 0.00015 seconds | ./spec/handlers/method_handler_spec.rb[1:31] | passed | 0.00012 seconds | ./spec/handlers/method_handler_spec.rb[1:32] | passed | 0.00023 seconds | ./spec/handlers/method_handler_spec.rb[1:33] | passed | 0.00023 seconds | ./spec/handlers/method_handler_spec.rb[1:34] | passed | 0.00019 seconds | ./spec/handlers/method_handler_spec.rb[1:35] | passed | 0.00031 seconds | ./spec/handlers/method_handler_spec.rb[1:36] | passed | 0.00015 seconds | ./spec/handlers/method_handler_spec.rb[1:37] | passed | 0.00032 seconds | ./spec/handlers/method_handler_spec.rb[1:38] | passed | 0.00014 seconds | ./spec/handlers/method_handler_spec.rb[1:39] | passed | 0.00009 seconds | ./spec/handlers/method_handler_spec.rb[1:40] | passed | 0.00019 seconds | ./spec/handlers/method_handler_spec.rb[1:41] | passed | 0.00058 seconds | ./spec/handlers/method_handler_spec.rb[1:42] | passed | 0.0001 seconds | ./spec/handlers/method_handler_spec.rb[1:43] | passed | 0.00009 seconds | ./spec/handlers/method_handler_spec.rb[1:44] | passed | 0.00011 seconds | ./spec/handlers/method_handler_spec.rb[1:45] | passed | 0.00006 seconds | ./spec/handlers/method_handler_spec.rb[1:46] | passed | 0.00009 seconds | ./spec/handlers/method_handler_spec.rb[1:47] | passed | 0.00129 seconds | ./spec/handlers/method_handler_spec.rb[1:48] | passed | 0.00012 seconds | ./spec/handlers/mixin_handler_spec.rb[1:1] | passed | 0.00017 seconds | ./spec/handlers/mixin_handler_spec.rb[1:2] | passed | 0.00013 seconds | ./spec/handlers/mixin_handler_spec.rb[1:3] | passed | 0.00024 seconds | ./spec/handlers/mixin_handler_spec.rb[1:4] | passed | 0.00014 seconds | ./spec/handlers/mixin_handler_spec.rb[1:5] | passed | 0.00009 seconds | ./spec/handlers/mixin_handler_spec.rb[1:6] | passed | 0.00012 seconds | ./spec/handlers/mixin_handler_spec.rb[1:7] | passed | 0.00008 seconds | ./spec/handlers/mixin_handler_spec.rb[1:8] | passed | 0.00014 seconds | ./spec/handlers/mixin_handler_spec.rb[1:9] | passed | 0.00034 seconds | ./spec/handlers/mixin_handler_spec.rb[1:10] | passed | 0.00101 seconds | ./spec/handlers/mixin_handler_spec.rb[1:11] | passed | 0.00065 seconds | ./spec/handlers/module_function_handler_spec.rb[1:1] | passed | 0.00164 seconds | ./spec/handlers/module_function_handler_spec.rb[1:2] | passed | 0.00167 seconds | ./spec/handlers/module_function_handler_spec.rb[1:3] | passed | 0.00182 seconds | ./spec/handlers/module_function_handler_spec.rb[1:4] | passed | 0.00212 seconds | ./spec/handlers/module_function_handler_spec.rb[1:5] | passed | 0.00091 seconds | ./spec/handlers/module_function_handler_spec.rb[1:6] | passed | 0.00102 seconds | ./spec/handlers/module_handler_spec.rb[1:1] | passed | 0.00011 seconds | ./spec/handlers/module_handler_spec.rb[1:2] | passed | 0.00007 seconds | ./spec/handlers/module_handler_spec.rb[1:3] | passed | 0.00009 seconds | ./spec/handlers/module_handler_spec.rb[1:4] | passed | 0.00007 seconds | ./spec/handlers/module_handler_spec.rb[1:5] | passed | 0.00007 seconds | ./spec/handlers/module_handler_spec.rb[1:6] | passed | 0.00021 seconds | ./spec/handlers/module_handler_spec.rb[1:7] | passed | 0.0001 seconds | ./spec/handlers/private_class_method_handler_spec.rb[1:1:1] | passed | 0.00237 seconds | ./spec/handlers/private_class_method_handler_spec.rb[1:1:2] | passed | 0.00306 seconds | ./spec/handlers/private_class_method_handler_spec.rb[1:2:1] | passed | 0.00326 seconds | ./spec/handlers/private_class_method_handler_spec.rb[1:3:1] | passed | 0.00183 seconds | ./spec/handlers/private_class_method_handler_spec.rb[1:3:2] | passed | 0.00148 seconds | ./spec/handlers/private_class_method_handler_spec.rb[1:3:3] | passed | 0.00172 seconds | ./spec/handlers/private_class_method_handler_spec.rb[1:3:4:1] | passed | 0.00165 seconds | ./spec/handlers/private_constant_handler_spec.rb[1:1] | passed | 0.00009 seconds | ./spec/handlers/private_constant_handler_spec.rb[1:2] | passed | 0.00009 seconds | ./spec/handlers/private_constant_handler_spec.rb[1:3] | passed | 0.00165 seconds | ./spec/handlers/private_constant_handler_spec.rb[1:4] | passed | 0.00102 seconds | ./spec/handlers/processor_spec.rb[1:1] | passed | 0.00015 seconds | ./spec/handlers/processor_spec.rb[1:2] | passed | 0.00011 seconds | ./spec/handlers/processor_spec.rb[1:3] | passed | 0.00014 seconds | ./spec/handlers/processor_spec.rb[1:4] | passed | 0.00012 seconds | ./spec/handlers/processor_spec.rb[1:5] | passed | 0.00053 seconds | ./spec/handlers/public_class_method_handler_spec.rb[1:1:1] | passed | 0.00228 seconds | ./spec/handlers/public_class_method_handler_spec.rb[1:1:2] | passed | 0.00342 seconds | ./spec/handlers/public_class_method_handler_spec.rb[1:2:1] | passed | 0.00328 seconds | ./spec/handlers/public_class_method_handler_spec.rb[1:3:1] | passed | 0.00126 seconds | ./spec/handlers/public_class_method_handler_spec.rb[1:3:2] | passed | 0.00134 seconds | ./spec/handlers/public_class_method_handler_spec.rb[1:3:3] | passed | 0.00128 seconds | ./spec/handlers/public_class_method_handler_spec.rb[1:3:4:1] | passed | 0.00118 seconds | ./spec/handlers/ruby/base_spec.rb[1:1] | passed | 0.00087 seconds | ./spec/handlers/ruby/base_spec.rb[1:2] | passed | 0.00085 seconds | ./spec/handlers/ruby/base_spec.rb[1:3] | passed | 0.00055 seconds | ./spec/handlers/ruby/base_spec.rb[1:4] | passed | 0.00051 seconds | ./spec/handlers/ruby/base_spec.rb[1:5] | passed | 0.00049 seconds | ./spec/handlers/ruby/base_spec.rb[1:6] | passed | 0.00125 seconds | ./spec/handlers/ruby/legacy/base_spec.rb[1:1] | passed | 0.00087 seconds | ./spec/handlers/ruby/legacy/base_spec.rb[1:2] | passed | 0.00164 seconds | ./spec/handlers/ruby/legacy/base_spec.rb[1:3] | passed | 0.00132 seconds | ./spec/handlers/ruby/legacy/base_spec.rb[1:4] | passed | 0.00117 seconds | ./spec/handlers/ruby/legacy/base_spec.rb[1:5] | passed | 0.0027 seconds | ./spec/handlers/visibility_handler_spec.rb[1:1] | passed | 0.00013 seconds | ./spec/handlers/visibility_handler_spec.rb[1:2] | passed | 0.00007 seconds | ./spec/handlers/visibility_handler_spec.rb[1:3] | passed | 0.00007 seconds | ./spec/handlers/visibility_handler_spec.rb[1:4] | passed | 0.00008 seconds | ./spec/handlers/visibility_handler_spec.rb[1:5] | passed | 0.00008 seconds | ./spec/handlers/visibility_handler_spec.rb[1:6] | passed | 0.00012 seconds | ./spec/handlers/visibility_handler_spec.rb[1:7] | passed | 0.00008 seconds | ./spec/handlers/visibility_handler_spec.rb[1:8] | passed | 0.00007 seconds | ./spec/handlers/yield_handler_spec.rb[1:1] | passed | 0.00014 seconds | ./spec/handlers/yield_handler_spec.rb[1:2] | passed | 0.00013 seconds | ./spec/handlers/yield_handler_spec.rb[1:3] | passed | 0.00022 seconds | ./spec/handlers/yield_handler_spec.rb[1:4] | passed | 0.00008 seconds | ./spec/handlers/yield_handler_spec.rb[1:5] | passed | 0.0001 seconds | ./spec/handlers/yield_handler_spec.rb[1:6] | passed | 0.00009 seconds | ./spec/handlers/yield_handler_spec.rb[1:7] | passed | 0.00016 seconds | ./spec/handlers/yield_handler_spec.rb[1:8] | passed | 0.00015 seconds | ./spec/i18n/locale_spec.rb[1:1:1] | passed | 0.00007 seconds | ./spec/i18n/locale_spec.rb[1:2:1] | passed | 0.00041 seconds | ./spec/i18n/locale_spec.rb[1:2:2] | passed | 0.03127 seconds | ./spec/i18n/locale_spec.rb[1:3:1] | passed | 0.0001 seconds | ./spec/i18n/locale_spec.rb[1:3:2] | passed | 0.0001 seconds | ./spec/i18n/message_spec.rb[1:1:1] | passed | 0.00011 seconds | ./spec/i18n/message_spec.rb[1:2:1] | passed | 0.0002 seconds | ./spec/i18n/message_spec.rb[1:3:1] | passed | 0.00007 seconds | ./spec/i18n/message_spec.rb[1:4:1] | passed | 0.00008 seconds | ./spec/i18n/messages_spec.rb[1:1:1] | passed | 0.00012 seconds | ./spec/i18n/messages_spec.rb[1:1:2] | passed | 0.00007 seconds | ./spec/i18n/messages_spec.rb[1:2:1] | passed | 0.00011 seconds | ./spec/i18n/messages_spec.rb[1:2:2] | passed | 0.00007 seconds | ./spec/i18n/messages_spec.rb[1:3:1] | passed | 0.00007 seconds | ./spec/i18n/messages_spec.rb[1:3:2] | passed | 0.0001 seconds | ./spec/i18n/messages_spec.rb[1:4:1] | passed | 0.00008 seconds | ./spec/i18n/pot_generator_spec.rb[1:1:1] | passed | 0.00108 seconds | ./spec/i18n/pot_generator_spec.rb[1:1:2] | passed | 0.00024 seconds | ./spec/i18n/pot_generator_spec.rb[1:2:1] | passed | 0.00017 seconds | ./spec/i18n/pot_generator_spec.rb[1:2:2] | passed | 0.00008 seconds | ./spec/i18n/pot_generator_spec.rb[1:2:3] | passed | 0.00012 seconds | ./spec/i18n/pot_generator_spec.rb[1:3:1] | passed | 0.00038 seconds | ./spec/i18n/pot_generator_spec.rb[1:3:2] | passed | 0.00034 seconds | ./spec/i18n/pot_generator_spec.rb[1:3:3] | passed | 0.00041 seconds | ./spec/i18n/pot_generator_spec.rb[1:3:4] | passed | 0.0005 seconds | ./spec/i18n/pot_generator_spec.rb[1:3:5] | passed | 0.00077 seconds | ./spec/i18n/pot_generator_spec.rb[1:3:6] | passed | 0.00329 seconds | ./spec/i18n/pot_generator_spec.rb[1:4:1] | passed | 0.00047 seconds | ./spec/i18n/pot_generator_spec.rb[1:4:2] | passed | 0.00044 seconds | ./spec/i18n/text_spec.rb[1:1:1:1] | passed | 0.00014 seconds | ./spec/i18n/text_spec.rb[1:1:1:2] | passed | 0.00009 seconds | ./spec/i18n/text_spec.rb[1:1:1:3] | passed | 0.00009 seconds | ./spec/i18n/text_spec.rb[1:1:2:1] | passed | 0.00013 seconds | ./spec/i18n/text_spec.rb[1:2:1:1] | passed | 0.0001 seconds | ./spec/i18n/text_spec.rb[1:2:1:2] | passed | 0.00013 seconds | ./spec/i18n/text_spec.rb[1:2:2:1] | passed | 0.00011 seconds | ./spec/i18n/text_spec.rb[1:2:2:2] | passed | 0.00012 seconds | ./spec/i18n/text_spec.rb[1:2:2:3] | passed | 0.00009 seconds | ./spec/logging_spec.rb[1:1:1] | passed | 0.00007 seconds | ./spec/logging_spec.rb[1:2:1] | passed | 0.00034 seconds | ./spec/logging_spec.rb[1:2:2] | passed | 0.00026 seconds | ./spec/logging_spec.rb[1:3:1] | passed | 0.00663 seconds | ./spec/options_spec.rb[1:1:1] | passed | 0.00012 seconds | ./spec/options_spec.rb[1:1:2] | passed | 0.0001 seconds | ./spec/options_spec.rb[1:2:1] | passed | 0.00012 seconds | ./spec/options_spec.rb[1:2:2] | passed | 0.0001 seconds | ./spec/options_spec.rb[1:3:1] | passed | 0.00007 seconds | ./spec/options_spec.rb[1:3:2] | passed | 0.00007 seconds | ./spec/options_spec.rb[1:4:1] | passed | 0.00014 seconds | ./spec/options_spec.rb[1:5:1] | passed | 0.00007 seconds | ./spec/options_spec.rb[1:5:2] | passed | 0.00011 seconds | ./spec/options_spec.rb[1:6:1] | passed | 0.00012 seconds | ./spec/options_spec.rb[1:6:2] | passed | 0.00007 seconds | ./spec/options_spec.rb[1:6:3] | passed | 0.00034 seconds | ./spec/options_spec.rb[1:7:1] | passed | 0.00007 seconds | ./spec/options_spec.rb[1:7:2] | passed | 0.00019 seconds | ./spec/options_spec.rb[1:8:1] | passed | 0.0001 seconds | ./spec/options_spec.rb[1:8:2] | passed | 0.00013 seconds | ./spec/options_spec.rb[1:9:1] | passed | 0.00013 seconds | ./spec/options_spec.rb[1:9:2] | passed | 0.00014 seconds | ./spec/options_spec.rb[1:9:3] | passed | 0.00009 seconds | ./spec/options_spec.rb[1:10:1] | passed | 0.00007 seconds | ./spec/parser/base_spec.rb[1:1:1] | passed | 0.00021 seconds | ./spec/parser/base_spec.rb[1:1:2] | passed | 0.00008 seconds | ./spec/parser/base_spec.rb[1:1:3] | passed | 0.00007 seconds | ./spec/parser/base_spec.rb[1:1:4] | passed | 0.00008 seconds | ./spec/parser/c_parser_spec.rb[1:1:1:1] | passed | 0.00016 seconds | ./spec/parser/c_parser_spec.rb[1:1:1:2] | passed | 0.00015 seconds | ./spec/parser/c_parser_spec.rb[1:1:1:3] | passed | 0.00015 seconds | ./spec/parser/c_parser_spec.rb[1:1:2:1] | passed | 0.00018 seconds | ./spec/parser/c_parser_spec.rb[1:1:2:2] | passed | 0.00009 seconds | ./spec/parser/c_parser_spec.rb[1:1:2:3] | passed | 0.00013 seconds | ./spec/parser/c_parser_spec.rb[1:1:3:1] | passed | 0.00263 seconds | ./spec/parser/c_parser_spec.rb[1:1:3:2] | passed | 0.00189 seconds | ./spec/parser/c_parser_spec.rb[1:1:3:3] | passed | 0.00225 seconds | ./spec/parser/c_parser_spec.rb[1:1:4:1] | passed | 0.00139 seconds | ./spec/parser/c_parser_spec.rb[1:1:5:1] | passed | 0.0013 seconds | ./spec/parser/c_parser_spec.rb[1:1:6:1] | passed | 0.00447 seconds | ./spec/parser/c_parser_spec.rb[1:1:7:1] | passed | 0.00157 seconds | ./spec/parser/c_parser_spec.rb[1:2:1] | passed | 0.00022 seconds | ./spec/parser/c_parser_spec.rb[1:2:2] | passed | 0.00021 seconds | ./spec/parser/c_parser_spec.rb[1:2:3] | passed | 0.0001 seconds | ./spec/parser/ruby/ast_node_spec.rb[1:1:1] | passed | 0.00011 seconds | ./spec/parser/ruby/ast_node_spec.rb[1:1:2] | passed | 0.0001 seconds | ./spec/parser/ruby/ast_node_spec.rb[1:2:1] | passed | 0.00059 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:1] | passed | 0.00151 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:2] | passed | 0.00058 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:3] | passed | 0.00069 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:4] | passed | 0.00104 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:5] | passed | 0.00214 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:6] | passed | 0.00279 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:7] | passed | 0.00388 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:8] | passed | 0.0007 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:9] | passed | 0.00109 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:10] | passed | 0.00057 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:11] | passed | 0.00079 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:12] | passed | 0.00159 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:13] | passed | 0.00063 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:14] | passed | 0.00056 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:15] | passed | 0.00076 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:16] | passed | 0.00223 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:17] | passed | 0.00305 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:18] | passed | 0.00213 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:19] | passed | 0.00079 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:20] | passed | 0.0008 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:21] | passed | 0.00081 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:22] | passed | 0.00309 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:23] | passed | 0.00084 seconds | ./spec/parser/ruby/legacy/statement_list_spec.rb[1:24] | passed | 0.003 seconds | ./spec/parser/ruby/legacy/token_list_spec.rb[1:1:1] | passed | 0.00081 seconds | ./spec/parser/ruby/legacy/token_list_spec.rb[1:1:2] | passed | 0.00015 seconds | ./spec/parser/ruby/legacy/token_list_spec.rb[1:1:3] | passed | 0.00134 seconds | ./spec/parser/ruby/legacy/token_list_spec.rb[1:1:4] | passed | 0.00012 seconds | ./spec/parser/ruby/legacy/token_list_spec.rb[1:1:5] | passed | 0.00052 seconds | ./spec/parser/ruby/legacy/token_list_spec.rb[1:1:6] | passed | 0.0005 seconds | ./spec/parser/ruby/legacy/token_list_spec.rb[1:2:1] | passed | 0.00012 seconds | ./spec/parser/ruby/legacy/token_list_spec.rb[1:2:2] | passed | 0.00008 seconds | ./spec/parser/ruby/legacy/token_list_spec.rb[1:2:3] | passed | 0.0001 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:1] | passed | 0.0006 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:2] | passed | 0.0008 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:3] | passed | 0.00019 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:4] | passed | 0.00015 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:5] | passed | 0.00027 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:6] | passed | 0.00022 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:7] | passed | 0.00018 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:8] | passed | 0.00016 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:9] | passed | 0.00038 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:10] | passed | 0.00022 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:11] | passed | 0.0001 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:12] | passed | 0.00015 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:13] | passed | 0.00056 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:14] | passed | 0.00023 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:15] | passed | 0.0003 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:16] | passed | 0.00025 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:17] | passed | 0.00021 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:18] | passed | 0.00023 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:19] | passed | 0.00023 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:20] | passed | 0.00021 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:21] | passed | 0.00036 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:22] | passed | 0.00039 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:23] | passed | 0.00011 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:24] | passed | 0.00021 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:25] | passed | 0.00054 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:26] | passed | 0.00041 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:27] | passed | 0.00045 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:28] | passed | 0.00025 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:29] | passed | 0.00022 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:30] | passed | 0.00016 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:31] | passed | 0.00021 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:32] | passed | 0.00023 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:33] | passed | 0.0002 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:34] | passed | 0.00019 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:35] | passed | 0.00022 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:36] | passed | 0.0002 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:37] | passed | 0.00076 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:38] | passed | 0.0002 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:39] | passed | 0.00083 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:40] | passed | 0.00024 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:41] | passed | 0.00075 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:42] | passed | 0.00021 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:43] | passed | 0.00078 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:44] | passed | 0.00022 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:45] | passed | 0.00027 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:46] | passed | 0.00027 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:47] | passed | 0.00029 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:48] | passed | 0.00028 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:49] | passed | 0.00016 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:50] | passed | 0.00014 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:51] | passed | 0.00031 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:52] | passed | 0.00087 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:53] | passed | 0.0011 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:54] | passed | 0.00124 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:55] | passed | 0.00077 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:56] | passed | 0.00133 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:57] | passed | 0.00135 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:58] | passed | 0.00145 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:59] | passed | 0.0011 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:60] | passed | 0.00141 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:61] | passed | 0.00105 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:62] | passed | 0.00124 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:63] | passed | 0.00112 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:64] | passed | 0.00097 seconds | ./spec/parser/ruby/ruby_parser_spec.rb[1:1:65] | passed | 0.00014 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:1] | passed | 0.00045 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:2] | passed | 0.0002 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:3] | passed | 0.00028 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:4] | passed | 0.00026 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:5] | passed | 0.00023 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:6] | passed | 0.00031 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:7] | passed | 0.00062 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:8] | passed | 0.00033 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:9] | passed | 0.00084 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:10] | passed | 0.00129 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:11] | passed | 0.00137 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:12] | passed | 0.00082 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:13] | passed | 0.00131 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:14] | passed | 0.00219 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:15] | passed | 0.00069 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:16] | passed | 0.00184 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:17] | passed | 0.00028 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:18] | passed | 0.00194 seconds | ./spec/parser/ruby/token_resolver_spec.rb[1:19] | passed | 0.00203 seconds | ./spec/parser/source_parser_spec.rb[1:1:1] | passed | 0.00164 seconds | ./spec/parser/source_parser_spec.rb[1:1:2] | passed | 0.00099 seconds | ./spec/parser/source_parser_spec.rb[1:1:3] | passed | 0.00025 seconds | ./spec/parser/source_parser_spec.rb[1:1:4] | passed | 0.0013 seconds | ./spec/parser/source_parser_spec.rb[1:1:5] | passed | 0.00115 seconds | ./spec/parser/source_parser_spec.rb[1:2:1] | passed | 0.00088 seconds | ./spec/parser/source_parser_spec.rb[1:2:2] | passed | 0.00098 seconds | ./spec/parser/source_parser_spec.rb[1:2:3] | passed | 0.001 seconds | ./spec/parser/source_parser_spec.rb[1:3:1] | passed | 0.00161 seconds | ./spec/parser/source_parser_spec.rb[1:3:2] | passed | 0.00104 seconds | ./spec/parser/source_parser_spec.rb[1:3:3] | passed | 0.00036 seconds | ./spec/parser/source_parser_spec.rb[1:3:4] | passed | 0.001 seconds | ./spec/parser/source_parser_spec.rb[1:4:1] | passed | 0.00116 seconds | ./spec/parser/source_parser_spec.rb[1:4:2] | passed | 0.00099 seconds | ./spec/parser/source_parser_spec.rb[1:4:3] | passed | 0.00117 seconds | ./spec/parser/source_parser_spec.rb[1:5:2] | passed | 0.00044 seconds | ./spec/parser/source_parser_spec.rb[1:5:3] | passed | 0.00014 seconds | ./spec/parser/source_parser_spec.rb[1:6:2] | passed | 0.00012 seconds | ./spec/parser/source_parser_spec.rb[1:6:3] | passed | 0.00024 seconds | ./spec/parser/source_parser_spec.rb[1:6:4] | passed | 0.00011 seconds | ./spec/parser/source_parser_spec.rb[1:6:5] | passed | 0.00012 seconds | ./spec/parser/source_parser_spec.rb[1:7:1] | passed | 0.00132 seconds | ./spec/parser/source_parser_spec.rb[1:7:2] | passed | 0.00122 seconds | ./spec/parser/source_parser_spec.rb[1:7:3] | passed | 0.00067 seconds | ./spec/parser/source_parser_spec.rb[1:7:4] | passed | 0.00088 seconds | ./spec/parser/source_parser_spec.rb[1:7:5] | passed | 0.00126 seconds | ./spec/parser/source_parser_spec.rb[1:7:6] | passed | 0.00053 seconds | ./spec/parser/source_parser_spec.rb[1:7:7] | passed | 0.00048 seconds | ./spec/parser/source_parser_spec.rb[1:7:8] | passed | 0.00147 seconds | ./spec/parser/source_parser_spec.rb[1:7:9] | passed | 0.001 seconds | ./spec/parser/source_parser_spec.rb[1:7:10] | passed | 0.00073 seconds | ./spec/parser/source_parser_spec.rb[1:7:11] | passed | 0.00074 seconds | ./spec/parser/source_parser_spec.rb[1:7:12] | passed | 0.00171 seconds | ./spec/parser/source_parser_spec.rb[1:7:13] | passed | 0.00242 seconds | ./spec/parser/source_parser_spec.rb[1:7:14] | passed | 0.00179 seconds | ./spec/parser/source_parser_spec.rb[1:7:15] | passed | 0.0011 seconds | ./spec/parser/source_parser_spec.rb[1:7:16] | passed | 0.00135 seconds | ./spec/parser/source_parser_spec.rb[1:8:1] | passed | 0.00167 seconds | ./spec/parser/source_parser_spec.rb[1:8:2] | passed | 0.00049 seconds | ./spec/parser/source_parser_spec.rb[1:8:3] | passed | 0.00184 seconds | ./spec/parser/source_parser_spec.rb[1:8:4] | passed | 0.00048 seconds | ./spec/parser/source_parser_spec.rb[1:8:5] | passed | 0.00127 seconds | ./spec/parser/source_parser_spec.rb[1:8:6] | passed | 0.00084 seconds | ./spec/parser/source_parser_spec.rb[1:8:7] | passed | 0.00051 seconds | ./spec/parser/source_parser_spec.rb[1:8:8] | passed | 0.00036 seconds | ./spec/parser/source_parser_spec.rb[1:8:9] | passed | 0.00755 seconds | ./spec/parser/source_parser_spec.rb[1:8:10] | passed | 0.00121 seconds | ./spec/parser/source_parser_spec.rb[1:8:11] | passed | 0.00094 seconds | ./spec/parser/source_parser_spec.rb[1:9:1] | passed | 0.00248 seconds | ./spec/parser/source_parser_spec.rb[1:9:2] | passed | 0.00119 seconds | ./spec/parser/source_parser_spec.rb[1:9:3] | passed | 0.00108 seconds | ./spec/parser/source_parser_spec.rb[1:10:1] | passed | 0.00033 seconds | ./spec/parser/source_parser_spec.rb[1:10:2] | passed | 0.00081 seconds | ./spec/parser/source_parser_spec.rb[1:10:3] | passed | 0.00203 seconds | ./spec/parser/source_parser_spec.rb[1:10:4] | passed | 0.00183 seconds | ./spec/parser/source_parser_spec.rb[1:10:5] | passed | 0.005 seconds | ./spec/parser/source_parser_spec.rb[1:10:6] | passed | 0.00166 seconds | ./spec/parser/source_parser_spec.rb[1:10:7] | passed | 0.00069 seconds | ./spec/parser/source_parser_spec.rb[1:10:8] | passed | 0.00088 seconds | ./spec/parser/tag_parsing_spec.rb[1:1] | passed | 0.00175 seconds | ./spec/parser/tag_parsing_spec.rb[1:2] | passed | 0.00147 seconds | ./spec/parser/tag_parsing_spec.rb[1:3] | passed | 0.00131 seconds | ./spec/rake/yardoc_task_spec.rb[1:1:1] | passed | 0.00081 seconds | ./spec/rake/yardoc_task_spec.rb[1:2:1] | passed | 0.00711 seconds | ./spec/rake/yardoc_task_spec.rb[1:3:1] | passed | 0.00797 seconds | ./spec/rake/yardoc_task_spec.rb[1:3:2] | passed | 0.00758 seconds | ./spec/rake/yardoc_task_spec.rb[1:4:1] | passed | 0.00781 seconds | ./spec/rake/yardoc_task_spec.rb[1:5:1] | passed | 0.00083 seconds | ./spec/rake/yardoc_task_spec.rb[1:6:1] | passed | 0.00072 seconds | ./spec/rake/yardoc_task_spec.rb[1:7:1] | passed | 0.00057 seconds | ./spec/rake/yardoc_task_spec.rb[1:7:2] | passed | 0.00074 seconds | ./spec/registry_spec.rb[1:1:1] | passed | 0.00051 seconds | ./spec/registry_spec.rb[1:1:2] | passed | 0.00031 seconds | ./spec/registry_spec.rb[1:1:3] | passed | 0.0005 seconds | ./spec/registry_spec.rb[1:1:4] | passed | 0.00043 seconds | ./spec/registry_spec.rb[1:1:5] | passed | 0.00048 seconds | ./spec/registry_spec.rb[1:1:6] | passed | 0.0004 seconds | ./spec/registry_spec.rb[1:1:7] | passed | 0.00055 seconds | ./spec/registry_spec.rb[1:1:8] | passed | 0.00044 seconds | ./spec/registry_spec.rb[1:1:9] | passed | 0.00051 seconds | ./spec/registry_spec.rb[1:1:10] | passed | 0.00148 seconds | ./spec/registry_spec.rb[1:1:11] | passed | 0.00056 seconds | ./spec/registry_spec.rb[1:1:12] | passed | 0.00053 seconds | ./spec/registry_spec.rb[1:2:1] | passed | 0.00009 seconds | ./spec/registry_spec.rb[1:3:1] | passed | 0.00019 seconds | ./spec/registry_spec.rb[1:4:1] | passed | 0.00024 seconds | ./spec/registry_spec.rb[1:4:2] | passed | 0.0003 seconds | ./spec/registry_spec.rb[1:4:3] | passed | 0.00026 seconds | ./spec/registry_spec.rb[1:4:4] | passed | 0.00014 seconds | ./spec/registry_spec.rb[1:4:5] | passed | 0.00137 seconds | ./spec/registry_spec.rb[1:4:6] | passed | 0.0066 seconds | ./spec/registry_spec.rb[1:4:7] | passed | 0.00204 seconds | ./spec/registry_spec.rb[1:4:8] | passed | 0.00132 seconds | ./spec/registry_spec.rb[1:4:9] | passed | 0.00194 seconds | ./spec/registry_spec.rb[1:4:10] | passed | 0.00177 seconds | ./spec/registry_spec.rb[1:4:11] | passed | 0.00214 seconds | ./spec/registry_spec.rb[1:4:12] | passed | 0.00154 seconds | ./spec/registry_spec.rb[1:4:13] | passed | 0.0022 seconds | ./spec/registry_spec.rb[1:4:14] | passed | 0.00052 seconds | ./spec/registry_spec.rb[1:4:15] | passed | 0.00157 seconds | ./spec/registry_spec.rb[1:4:16] | passed | 0.00068 seconds | ./spec/registry_spec.rb[1:4:17] | passed | 0.0011 seconds | ./spec/registry_spec.rb[1:4:18] | passed | 0.00032 seconds | ./spec/registry_spec.rb[1:4:19] | passed | 0.0004 seconds | ./spec/registry_spec.rb[1:5:1] | passed | 0.00027 seconds | ./spec/registry_spec.rb[1:5:2] | passed | 0.00024 seconds | ./spec/registry_spec.rb[1:5:3] | passed | 0.00023 seconds | ./spec/registry_spec.rb[1:6:1] | passed | 0.00022 seconds | ./spec/registry_spec.rb[1:7:1] | passed | 0.0003 seconds | ./spec/registry_spec.rb[1:7:2] | passed | 0.00044 seconds | ./spec/registry_spec.rb[1:7:3] | passed | 0.00527 seconds | ./spec/registry_spec.rb[1:8:1] | passed | 0.00023 seconds | ./spec/registry_spec.rb[1:9:1] | passed | 0.00008 seconds | ./spec/registry_spec.rb[1:10:1] | passed | 0.00018 seconds | ./spec/registry_spec.rb[1:11:1] | passed | 0.00139 seconds | ./spec/registry_spec.rb[1:11:2] | passed | 0.00089 seconds | ./spec/registry_spec.rb[1:12:1] | passed | 0.00008 seconds | ./spec/registry_spec.rb[1:13:1] | passed | 0.00025 seconds | ./spec/registry_spec.rb[1:14:1] | passed | 0.20204 seconds | ./spec/registry_spec.rb[1:14:2] | passed | 0.1994 seconds | ./spec/registry_spec.rb[1:14:3] | passed | 0.00052 seconds | ./spec/registry_spec.rb[1:14:4] | passed | 0.19956 seconds | ./spec/registry_store_spec.rb[1:1:1] | passed | 0.00115 seconds | ./spec/registry_store_spec.rb[1:1:2] | passed | 0.00077 seconds | ./spec/registry_store_spec.rb[1:1:3] | passed | 0.00081 seconds | ./spec/registry_store_spec.rb[1:1:4] | passed | 0.00069 seconds | ./spec/registry_store_spec.rb[1:1:5] | passed | 0.00079 seconds | ./spec/registry_store_spec.rb[1:1:6] | passed | 0.00051 seconds | ./spec/registry_store_spec.rb[1:1:7] | passed | 0.00047 seconds | ./spec/registry_store_spec.rb[1:1:8] | passed | 0.001 seconds | ./spec/registry_store_spec.rb[1:1:9] | passed | 0.00095 seconds | ./spec/registry_store_spec.rb[1:1:10] | passed | 0.00116 seconds | ./spec/registry_store_spec.rb[1:2:1] | passed | 0.00649 seconds | ./spec/registry_store_spec.rb[1:2:2] | passed | 0.04137 seconds | ./spec/registry_store_spec.rb[1:2:3] | passed | 0.03684 seconds | ./spec/registry_store_spec.rb[1:2:4] | passed | 0.95515 seconds | ./spec/registry_store_spec.rb[1:3:1] | passed | 0.00154 seconds | ./spec/registry_store_spec.rb[1:3:2] | passed | 0.00049 seconds | ./spec/registry_store_spec.rb[1:4:1] | passed | 0.00043 seconds | ./spec/registry_store_spec.rb[1:4:2] | passed | 0.00071 seconds | ./spec/registry_store_spec.rb[1:5:1] | passed | 0.00099 seconds | ./spec/registry_store_spec.rb[1:5:2] | passed | 0.00136 seconds | ./spec/registry_store_spec.rb[1:6:1] | passed | 0.00085 seconds | ./spec/registry_store_spec.rb[1:6:2] | passed | 0.00072 seconds | ./spec/registry_store_spec.rb[1:7:1] | passed | 0.00083 seconds | ./spec/registry_store_spec.rb[1:7:2] | passed | 0.00046 seconds | ./spec/registry_store_spec.rb[1:7:3] | passed | 0.00061 seconds | ./spec/registry_store_spec.rb[1:8:1] | passed | 0.00044 seconds | ./spec/registry_store_spec.rb[1:9:1] | passed | 0.00182 seconds | ./spec/registry_store_spec.rb[1:10:1] | passed | 0.00073 seconds | ./spec/registry_store_spec.rb[1:10:2] | passed | 0.00058 seconds | ./spec/registry_store_spec.rb[1:10:3] | passed | 0.00064 seconds | ./spec/registry_store_spec.rb[1:10:4] | passed | 0.00054 seconds | ./spec/registry_store_spec.rb[1:11:1] | passed | 0.00065 seconds | ./spec/serializers/file_system_serializer_spec.rb[1:1:1] | passed | 0.00021 seconds | ./spec/serializers/file_system_serializer_spec.rb[1:2:1] | passed | 0.00019 seconds | ./spec/serializers/file_system_serializer_spec.rb[1:3:1] | passed | 0.00126 seconds | ./spec/serializers/file_system_serializer_spec.rb[1:3:2] | passed | 0.00029 seconds | ./spec/serializers/file_system_serializer_spec.rb[1:3:3] | passed | 0.00019 seconds | ./spec/serializers/file_system_serializer_spec.rb[1:3:4] | passed | 0.00117 seconds | ./spec/serializers/file_system_serializer_spec.rb[1:3:5] | passed | 0.00027 seconds | ./spec/serializers/file_system_serializer_spec.rb[1:3:6] | passed | 0.00028 seconds | ./spec/serializers/file_system_serializer_spec.rb[1:3:7] | passed | 0.00131 seconds | ./spec/serializers/file_system_serializer_spec.rb[1:3:8] | passed | 0.00077 seconds | ./spec/serializers/file_system_serializer_spec.rb[1:3:9] | passed | 0.00454 seconds | ./spec/serializers/file_system_serializer_spec.rb[1:4:1] | passed | 0.00176 seconds | ./spec/serializers/file_system_serializer_spec.rb[1:4:2] | passed | 0.00113 seconds | ./spec/serializers/yardoc_serializer_spec.rb[1:1:1] | passed | 0.00042 seconds | ./spec/serializers/yardoc_serializer_spec.rb[1:1:2] | passed | 0.00057 seconds | ./spec/serializers/yardoc_serializer_spec.rb[1:2:1] | passed | 0.0008 seconds | ./spec/serializers/yardoc_serializer_spec.rb[1:3:1] | passed | 0.00058 seconds | ./spec/serializers/yardoc_serializer_spec.rb[1:4:1] | passed | 0.00046 seconds | ./spec/serializers/yardoc_serializer_spec.rb[1:4:2] | passed | 0.00047 seconds | ./spec/serializers/yardoc_serializer_spec.rb[1:4:3] | passed | 0.00054 seconds | ./spec/server/adapter_spec.rb[1:1:1] | passed | 0.00013 seconds | ./spec/server/adapter_spec.rb[1:2:1] | passed | 0.00011 seconds | ./spec/server/adapter_spec.rb[1:3:1] | passed | 0.00009 seconds | ./spec/server/adapter_spec.rb[1:4:1] | passed | 0.00018 seconds | ./spec/server/commands/base_spec.rb[1:1:1] | passed | 0.00018 seconds | ./spec/server/commands/base_spec.rb[1:1:2] | passed | 0.00045 seconds | ./spec/server/commands/base_spec.rb[1:1:3] | passed | 0.00046 seconds | ./spec/server/commands/base_spec.rb[1:2:1] | passed | 0.00015 seconds | ./spec/server/commands/base_spec.rb[1:3:1] | passed | 0.0001 seconds | ./spec/server/commands/base_spec.rb[1:3:2] | passed | 0.0001 seconds | ./spec/server/commands/base_spec.rb[1:3:3] | passed | 0.0001 seconds | ./spec/server/commands/base_spec.rb[1:3:4] | passed | 0.00017 seconds | ./spec/server/commands/base_spec.rb[1:3:5] | passed | 0.00008 seconds | ./spec/server/commands/base_spec.rb[1:3:6] | passed | 0.00016 seconds | ./spec/server/commands/library_command_spec.rb[1:1:1] | passed | 0.05999 seconds | ./spec/server/commands/library_command_spec.rb[1:1:2] | passed | 0.06062 seconds | ./spec/server/commands/library_command_spec.rb[1:1:3] | passed | 0.09233 seconds | ./spec/server/doc_server_helper_spec.rb[1:1:1] | passed | 0.0002 seconds | ./spec/server/doc_server_helper_spec.rb[1:1:2] | passed | 0.00056 seconds | ./spec/server/doc_server_helper_spec.rb[1:1:3] | passed | 0.00048 seconds | ./spec/server/doc_server_helper_spec.rb[1:2:1] | passed | 0.00016 seconds | ./spec/server/doc_server_helper_spec.rb[1:2:2] | passed | 0.00013 seconds | ./spec/server/doc_server_helper_spec.rb[1:2:3] | passed | 0.00014 seconds | ./spec/server/doc_server_serializer_spec.rb[1:1:1] | passed | 0.00016 seconds | ./spec/server/doc_server_serializer_spec.rb[1:1:2] | passed | 0.00182 seconds | ./spec/server/doc_server_serializer_spec.rb[1:1:3] | passed | 0.00025 seconds | ./spec/server/doc_server_serializer_spec.rb[1:1:4] | passed | 0.00017 seconds | ./spec/server/doc_server_serializer_spec.rb[1:1:5] | passed | 0.00014 seconds | ./spec/server/doc_server_serializer_spec.rb[1:1:6] | passed | 0.0002 seconds | ./spec/server/doc_server_serializer_spec.rb[1:1:7] | passed | 0.00022 seconds | ./spec/server/doc_server_serializer_spec.rb[1:1:8] | passed | 0.00018 seconds | ./spec/server/doc_server_serializer_spec.rb[1:1:9] | passed | 0.00736 seconds | ./spec/server/rack_adapter_spec.rb[1:1] | passed | 0.04351 seconds | ./spec/server/rack_adapter_spec.rb[1:2] | passed | 0.00224 seconds | ./spec/server/router_spec.rb[1:1:1] | passed | 0.00018 seconds | ./spec/server/router_spec.rb[1:1:2] | passed | 0.00012 seconds | ./spec/server/router_spec.rb[1:1:3] | passed | 0.00012 seconds | ./spec/server/router_spec.rb[1:1:4] | passed | 0.00013 seconds | ./spec/server/router_spec.rb[1:1:5] | passed | 0.00031 seconds | ./spec/server/router_spec.rb[1:2:1] | passed | 0.00233 seconds | ./spec/server/router_spec.rb[1:2:2] | passed | 0.00025 seconds | ./spec/server/router_spec.rb[1:2:3] | passed | 0.00032 seconds | ./spec/server/router_spec.rb[1:2:4] | passed | 0.00032 seconds | ./spec/server/router_spec.rb[1:2:5] | passed | 0.00026 seconds | ./spec/server/router_spec.rb[1:2:6] | passed | 0.00122 seconds | ./spec/server/router_spec.rb[1:2:7] | passed | 0.0003 seconds | ./spec/server/router_spec.rb[1:2:8] | passed | 0.00026 seconds | ./spec/server/router_spec.rb[1:2:9] | passed | 0.00027 seconds | ./spec/server/router_spec.rb[1:2:10] | passed | 0.00158 seconds | ./spec/server/router_spec.rb[1:2:11] | passed | 0.0003 seconds | ./spec/server/router_spec.rb[1:2:12] | passed | 0.00023 seconds | ./spec/server/static_caching_spec.rb[1:1:1] | passed | 0.00009 seconds | ./spec/server/static_caching_spec.rb[1:1:2] | passed | 0.0003 seconds | ./spec/server/static_caching_spec.rb[1:1:3] | passed | 0.00026 seconds | ./spec/server/static_caching_spec.rb[1:1:4] | passed | 0.0002 seconds | ./spec/server/static_caching_spec.rb[1:1:5] | passed | 0.00018 seconds | ./spec/server/webrick_servlet_spec.rb[1:1:1] | passed | 0.00018 seconds | ./spec/server_spec.rb[1:1:1] | passed | 0.00006 seconds | ./spec/server_spec.rb[1:1:2] | passed | 0.00006 seconds | ./spec/tags/default_factory_spec.rb[1:1:1] | passed | 0.00012 seconds | ./spec/tags/default_factory_spec.rb[1:2:1] | passed | 0.00013 seconds | ./spec/tags/default_factory_spec.rb[1:2:2] | passed | 0.0001 seconds | ./spec/tags/default_factory_spec.rb[1:2:3] | passed | 0.00011 seconds | ./spec/tags/default_factory_spec.rb[1:2:4] | passed | 0.00008 seconds | ./spec/tags/default_factory_spec.rb[1:2:5] | passed | 0.00007 seconds | ./spec/tags/default_factory_spec.rb[1:2:6] | passed | 0.00008 seconds | ./spec/tags/default_factory_spec.rb[1:2:7] | passed | 0.00007 seconds | ./spec/tags/default_factory_spec.rb[1:2:8] | passed | 0.00007 seconds | ./spec/tags/default_factory_spec.rb[1:2:9] | passed | 0.00007 seconds | ./spec/tags/default_factory_spec.rb[1:2:10] | passed | 0.00007 seconds | ./spec/tags/default_factory_spec.rb[1:2:11] | passed | 0.0001 seconds | ./spec/tags/default_factory_spec.rb[1:2:12] | passed | 0.00012 seconds | ./spec/tags/default_factory_spec.rb[1:2:13] | passed | 0.00014 seconds | ./spec/tags/default_factory_spec.rb[1:2:14] | passed | 0.00009 seconds | ./spec/tags/default_factory_spec.rb[1:2:15] | passed | 0.00013 seconds | ./spec/tags/default_factory_spec.rb[1:2:16] | passed | 0.00015 seconds | ./spec/tags/default_factory_spec.rb[1:2:17] | passed | 0.00011 seconds | ./spec/tags/default_factory_spec.rb[1:2:18] | passed | 0.00009 seconds | ./spec/tags/default_factory_spec.rb[1:2:19] | passed | 0.00014 seconds | ./spec/tags/default_factory_spec.rb[1:2:20] | passed | 0.00013 seconds | ./spec/tags/default_factory_spec.rb[1:3:1] | passed | 0.00027 seconds | ./spec/tags/default_factory_spec.rb[1:3:2] | passed | 0.00017 seconds | ./spec/tags/default_factory_spec.rb[1:3:3] | passed | 0.00018 seconds | ./spec/tags/default_factory_spec.rb[1:3:4] | passed | 0.00012 seconds | ./spec/tags/default_factory_spec.rb[1:4:1] | passed | 0.00019 seconds | ./spec/tags/default_factory_spec.rb[1:4:2] | passed | 0.00017 seconds | ./spec/tags/default_factory_spec.rb[1:4:3] | passed | 0.00021 seconds | ./spec/tags/default_factory_spec.rb[1:4:4] | passed | 0.00019 seconds | ./spec/tags/default_factory_spec.rb[1:4:5] | passed | 0.00019 seconds | ./spec/tags/default_factory_spec.rb[1:5:1] | passed | 0.00011 seconds | ./spec/tags/default_factory_spec.rb[1:5:2] | passed | 0.00011 seconds | ./spec/tags/default_factory_spec.rb[1:5:3] | passed | 0.00009 seconds | ./spec/tags/default_tag_spec.rb[1:1] | passed | 0.00007 seconds | ./spec/tags/directives_spec.rb[1:1:1] | passed | 0.00074 seconds | ./spec/tags/directives_spec.rb[1:1:2] | passed | 0.0014 seconds | ./spec/tags/directives_spec.rb[1:1:3] | passed | 0.00123 seconds | ./spec/tags/directives_spec.rb[2:1:1] | passed | 0.00011 seconds | ./spec/tags/directives_spec.rb[2:1:2] | passed | 0.00011 seconds | ./spec/tags/directives_spec.rb[3:1:1] | passed | 0.00009 seconds | ./spec/tags/directives_spec.rb[3:1:2] | passed | 0.00011 seconds | ./spec/tags/directives_spec.rb[4:1:1] | passed | 0.00019 seconds | ./spec/tags/directives_spec.rb[4:1:2] | passed | 0.00028 seconds | ./spec/tags/directives_spec.rb[4:1:3] | passed | 0.00021 seconds | ./spec/tags/directives_spec.rb[4:1:4] | passed | 0.00022 seconds | ./spec/tags/directives_spec.rb[4:1:5] | passed | 0.00013 seconds | ./spec/tags/directives_spec.rb[4:1:6] | passed | 0.00026 seconds | ./spec/tags/directives_spec.rb[4:1:7] | passed | 0.00031 seconds | ./spec/tags/directives_spec.rb[4:1:8] | passed | 0.00034 seconds | ./spec/tags/directives_spec.rb[4:1:9] | passed | 0.00147 seconds | ./spec/tags/directives_spec.rb[4:1:10] | passed | 0.00126 seconds | ./spec/tags/directives_spec.rb[4:1:11] | passed | 0.0009 seconds | ./spec/tags/directives_spec.rb[4:1:12] | passed | 0.00076 seconds | ./spec/tags/directives_spec.rb[4:1:13] | passed | 0.00016 seconds | ./spec/tags/directives_spec.rb[5:1:1] | passed | 0.00119 seconds | ./spec/tags/directives_spec.rb[5:1:2] | passed | 0.0011 seconds | ./spec/tags/directives_spec.rb[5:1:3] | passed | 0.00187 seconds | ./spec/tags/directives_spec.rb[5:1:4] | passed | 0.00167 seconds | ./spec/tags/directives_spec.rb[5:1:5] | passed | 0.00238 seconds | ./spec/tags/directives_spec.rb[5:1:6] | passed | 0.00208 seconds | ./spec/tags/directives_spec.rb[5:1:7] | passed | 0.00103 seconds | ./spec/tags/directives_spec.rb[5:1:8] | passed | 0.00119 seconds | ./spec/tags/directives_spec.rb[6:1:1] | passed | 0.00197 seconds | ./spec/tags/directives_spec.rb[6:1:2] | passed | 0.00101 seconds | ./spec/tags/directives_spec.rb[6:1:3] | passed | 0.00197 seconds | ./spec/tags/directives_spec.rb[6:1:4] | passed | 0.00133 seconds | ./spec/tags/directives_spec.rb[6:2] | passed | 0.00218 seconds | ./spec/tags/directives_spec.rb[7:1:1] | passed | 0.00017 seconds | ./spec/tags/directives_spec.rb[7:1:2] | passed | 0.00024 seconds | ./spec/tags/directives_spec.rb[7:1:3] | passed | 0.00019 seconds | ./spec/tags/directives_spec.rb[7:1:4] | passed | 0.00013 seconds | ./spec/tags/directives_spec.rb[7:1:5] | passed | 0.00013 seconds | ./spec/tags/directives_spec.rb[7:1:6] | passed | 0.0002 seconds | ./spec/tags/directives_spec.rb[7:1:7] | passed | 0.00013 seconds | ./spec/tags/directives_spec.rb[7:1:8] | passed | 0.00012 seconds | ./spec/tags/directives_spec.rb[7:1:9] | passed | 0.00012 seconds | ./spec/tags/directives_spec.rb[7:1:10] | passed | 0.00012 seconds | ./spec/tags/directives_spec.rb[7:1:11] | passed | 0.00011 seconds | ./spec/tags/directives_spec.rb[8:1:1] | passed | 0.00013 seconds | ./spec/tags/directives_spec.rb[8:1:2] | passed | 0.00025 seconds | ./spec/tags/directives_spec.rb[8:1:3] | passed | 0.00018 seconds | ./spec/tags/directives_spec.rb[8:1:4] | passed | 0.00012 seconds | ./spec/tags/directives_spec.rb[8:1:5] | passed | 0.00012 seconds | ./spec/tags/directives_spec.rb[8:1:6] | passed | 0.00012 seconds | ./spec/tags/directives_spec.rb[8:1:7] | passed | 0.00011 seconds | ./spec/tags/directives_spec.rb[8:1:8] | passed | 0.00011 seconds | ./spec/tags/directives_spec.rb[8:1:9] | passed | 0.0001 seconds | ./spec/tags/directives_spec.rb[8:1:10] | passed | 0.00011 seconds | ./spec/tags/directives_spec.rb[8:1:11] | passed | 0.0001 seconds | ./spec/tags/directives_spec.rb[8:1:12] | passed | 0.002 seconds | ./spec/tags/library_spec.rb[1:1:1] | passed | 0.00014 seconds | ./spec/tags/library_spec.rb[1:1:2] | passed | 0.00009 seconds | ./spec/tags/library_spec.rb[1:1:3] | passed | 0.00012 seconds | ./spec/tags/library_spec.rb[1:2:1] | passed | 0.00108 seconds | ./spec/tags/library_spec.rb[1:3:1] | passed | 0.0003 seconds | ./spec/tags/library_spec.rb[1:3:2] | passed | 0.0001 seconds | ./spec/tags/library_spec.rb[1:3:3] | passed | 0.00011 seconds | ./spec/tags/overload_tag_spec.rb[1:1] | passed | 0.00081 seconds | ./spec/tags/overload_tag_spec.rb[1:2] | passed | 0.00083 seconds | ./spec/tags/overload_tag_spec.rb[1:3] | passed | 0.00079 seconds | ./spec/tags/overload_tag_spec.rb[1:4] | passed | 0.00086 seconds | ./spec/tags/overload_tag_spec.rb[1:5] | passed | 0.00076 seconds | ./spec/tags/overload_tag_spec.rb[1:6] | passed | 0.00087 seconds | ./spec/tags/overload_tag_spec.rb[1:7] | passed | 0.00086 seconds | ./spec/tags/ref_tag_list_spec.rb[1:1] | passed | 0.00024 seconds | ./spec/tags/ref_tag_list_spec.rb[1:2] | passed | 0.0002 seconds | ./spec/tags/ref_tag_list_spec.rb[1:3] | passed | 0.00032 seconds | ./spec/tags/ref_tag_list_spec.rb[1:4] | passed | 0.0003 seconds | ./spec/tags/ref_tag_list_spec.rb[1:5] | passed | 0.00035 seconds | ./spec/tags/types_explainer_spec.rb[1:1:1] | passed | 0.0001 seconds | ./spec/tags/types_explainer_spec.rb[1:1:2] | passed | 0.00006 seconds | ./spec/tags/types_explainer_spec.rb[1:1:3] | passed | 0.00008 seconds | ./spec/tags/types_explainer_spec.rb[1:2:1] | passed | 0.00007 seconds | ./spec/tags/types_explainer_spec.rb[1:2:2] | passed | 0.00007 seconds | ./spec/tags/types_explainer_spec.rb[1:2:3] | passed | 0.00008 seconds | ./spec/tags/types_explainer_spec.rb[1:3:1] | passed | 0.00014 seconds | ./spec/tags/types_explainer_spec.rb[1:3:2] | passed | 0.00007 seconds | ./spec/tags/types_explainer_spec.rb[1:3:3] | passed | 0.00007 seconds | ./spec/tags/types_explainer_spec.rb[1:4:1] | passed | 0.00012 seconds | ./spec/tags/types_explainer_spec.rb[1:4:2] | passed | 0.00008 seconds | ./spec/tags/types_explainer_spec.rb[1:4:3] | passed | 0.00007 seconds | ./spec/tags/types_explainer_spec.rb[1:5:1] | passed | 0.00009 seconds | ./spec/tags/types_explainer_spec.rb[1:5:2] | passed | 0.00007 seconds | ./spec/tags/types_explainer_spec.rb[1:5:3] | passed | 0.00013 seconds | ./spec/tags/types_explainer_spec.rb[1:5:4] | passed | 0.00008 seconds | ./spec/tags/types_explainer_spec.rb[1:5:5] | passed | 0.00007 seconds | ./spec/tags/types_explainer_spec.rb[1:5:6] | passed | 0.00007 seconds | ./spec/tags/types_explainer_spec.rb[1:5:7] | passed | 0.00007 seconds | ./spec/tags/types_explainer_spec.rb[1:5:8] | passed | 0.0001 seconds | ./spec/tags/types_explainer_spec.rb[1:5:9] | passed | 0.00008 seconds | ./spec/tags/types_explainer_spec.rb[1:5:10] | passed | 0.00007 seconds | ./spec/tags/types_explainer_spec.rb[1:5:11] | passed | 0.00007 seconds | ./spec/tags/types_explainer_spec.rb[1:6:1] | passed | 0.00014 seconds | ./spec/tags/types_explainer_spec.rb[1:6:2] | passed | 0.0003 seconds | ./spec/templates/class_spec.rb[1:1] | passed | 0.04022 seconds | ./spec/templates/class_spec.rb[1:2] | passed | 0.01089 seconds | ./spec/templates/class_spec.rb[1:3] | passed | 0.0125 seconds | ./spec/templates/constant_spec.rb[1:1:1] | passed | 0.00991 seconds | ./spec/templates/constant_spec.rb[1:2:1] | passed | 0.00409 seconds | ./spec/templates/engine_spec.rb[1:1:1] | passed | 0.0001 seconds | ./spec/templates/engine_spec.rb[1:1:2] | passed | 0.001 seconds | ./spec/templates/engine_spec.rb[1:2:1] | passed | 0.00085 seconds | ./spec/templates/engine_spec.rb[1:2:2] | passed | 0.00082 seconds | ./spec/templates/engine_spec.rb[1:3:1] | passed | 0.00043 seconds | ./spec/templates/engine_spec.rb[1:3:2] | passed | 0.00063 seconds | ./spec/templates/engine_spec.rb[1:3:3] | passed | 0.0009 seconds | ./spec/templates/engine_spec.rb[1:3:4] | passed | 0.00425 seconds | ./spec/templates/engine_spec.rb[1:3:5] | passed | 0.00035 seconds | ./spec/templates/engine_spec.rb[1:4:1] | passed | 0.00044 seconds | ./spec/templates/engine_spec.rb[1:5:1] | passed | 0.00038 seconds | ./spec/templates/engine_spec.rb[1:5:2] | passed | 0.00039 seconds | ./spec/templates/engine_spec.rb[1:5:3] | passed | 0.00041 seconds | ./spec/templates/engine_spec.rb[1:5:4] | passed | 0.00038 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:1:1] | passed | 0.00061 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:1:2] | passed | 0.00099 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:1:3] | passed | 0.00028 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:2:1] | passed | 0.0001 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:3:1] | passed | 0.00016 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:3:2] | passed | 0.00021 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:3:3] | passed | 0.00034 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:3:4] | passed | 0.00006 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:4:1] | passed | 0.00006 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:5:1] | passed | 0.00026 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:5:2] | passed | 0.00018 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:5:3] | passed | 0.00015 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:5:4] | passed | 0.00036 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:5:5] | passed | 0.00034 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:5:6] | passed | 0.00025 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:5:7] | passed | 0.00025 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:5:8] | passed | 0.00041 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:5:9] | passed | 0.00027 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:5:10] | passed | 0.00038 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:6:1] | passed | 0.0001 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:6:2] | passed | 0.00016 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:6:3] | passed | 0.00009 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:7:1] | passed | 0.0003 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:7:2] | passed | 0.00024 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:7:3] | passed | 0.00018 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:8:1] | passed | 0.00011 seconds | ./spec/templates/helpers/base_helper_spec.rb[1:8:2] | passed | 0.00013 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:1:1] | passed | 0.00015 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:2:1] | passed | 0.00019 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:2:2] | passed | 0.00014 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:2:3] | passed | 0.00021 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:2:4] | passed | 0.00014 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:2:5] | passed | 0.0002 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:2:6] | passed | 0.00009 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:3:1] | passed | 0.0003 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:3:2] | passed | 0.0002 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:3:3] | passed | 0.00021 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:3:4] | passed | 0.00017 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:3:5] | passed | 0.00037 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:3:6] | passed | 0.00082 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:3:7] | passed | 0.00113 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:4:1] | passed | 0.07004 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:4:2] | passed | 0.00023 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:4:3] | passed | 0.01193 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:4:4] | passed | 0.00024 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:4:5] | passed | 0.00009 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:4:6] | passed | 0.00007 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:4:7] | passed | 0.00043 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:4:8] | passed | 0.00098 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:4:9] | passed | 0.00068 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:4:10] | passed | 0.00021 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:4:11] | passed | 0.00037 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:4:12] | passed | 0.00015 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:4:13] | passed | 0.00049 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:5:1] | passed | 0.00035 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:5:2] | passed | 0.00019 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:5:3] | passed | 0.00438 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:5:4] | passed | 0.00103 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:5:5] | passed | 0.00189 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:5:6] | passed | 0.00211 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:5:7] | passed | 0.00098 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:5:8] | passed | 0.00269 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:6:1] | passed | 0.00093 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:6:2] | passed | 0.00077 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:6:3] | passed | 0.00109 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:6:4] | passed | 0.00037 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:6:5] | passed | 0.00048 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:6:6] | passed | 0.0006 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:7:1] | passed | 0.0001 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:8:1] | passed | 0.00007 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:8:2] | passed | 0.00009 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:8:3] | passed | 0.00271 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:8:4] | passed | 0.00018 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:8:5] | passed | 0.0003 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:8:6] | passed | 0.00007 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:8:7] | passed | 0.00021 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:8:8] | passed | 0.00007 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:8:9] | passed | 0.00015 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:8:10] | passed | 0.00006 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:8:11] | passed | 0.00016 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:8:12] | passed | 0.00024 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:8:13] | passed | 0.00011 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:8:14] | passed | 0.00018 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:8:15] | passed | 0.00203 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:8:16] | passed | 0.00613 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:8:17] | passed | 0.0007 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:9:1:1] | passed | 0.00079 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:9:1:2] | passed | 0.00065 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:9:1:3] | passed | 0.00064 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:9:1:4] | passed | 0.00174 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:9:1:5] | passed | 0.00117 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:9:1:6] | passed | 0.00082 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:9:1:7] | passed | 0.00084 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:9:1:8] | passed | 0.00072 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:9:1:9] | passed | 0.00085 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:9:1:10] | passed | 0.00086 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:9:1:11] | passed | 0.00141 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:9:1:12] | passed | 0.00082 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:9:1:13] | passed | 0.00073 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:9:1:14] | passed | 0.00134 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:9:1:15] | passed | 0.00141 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:9:2] | passed | 0.00378 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:10:1] | passed | 0.00028 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:10:2] | passed | 0.00075 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:10:3] | passed | 0.0007 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:10:4] | passed | 0.00044 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:10:5] | passed | 0.00026 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:10:6] | passed | 0.00028 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:10:7] | passed | 0.00024 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:10:8] | passed | 0.00033 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:10:9] | passed | 0.00021 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:10:10] | passed | 0.00023 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:10:11] | passed | 0.00014 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:10:12] | passed | 0.00014 seconds | ./spec/templates/helpers/html_helper_spec.rb[1:11:1] | passed | 0.00017 seconds | ./spec/templates/helpers/html_syntax_highlight_helper_spec.rb[1:1:1] | passed | 0.00037 seconds | ./spec/templates/helpers/html_syntax_highlight_helper_spec.rb[1:1:2] | passed | 0.00391 seconds | ./spec/templates/helpers/html_syntax_highlight_helper_spec.rb[1:1:3] | passed | 0.00094 seconds | ./spec/templates/helpers/html_syntax_highlight_helper_spec.rb[1:1:4] | passed | 0.00053 seconds | ./spec/templates/helpers/html_syntax_highlight_helper_spec.rb[1:1:5] | passed | 0.00052 seconds | ./spec/templates/helpers/html_syntax_highlight_helper_spec.rb[1:1:6] | passed | 0.00092 seconds | ./spec/templates/helpers/markup/rdoc_markup_spec.rb[1:1:1] | passed | 0.00058 seconds | ./spec/templates/helpers/markup/rdoc_markup_spec.rb[1:1:2] | passed | 0.00016 seconds | ./spec/templates/helpers/markup/rdoc_markup_spec.rb[1:1:3] | passed | 0.00041 seconds | ./spec/templates/helpers/markup/rdoc_markup_spec.rb[1:1:4] | passed | 0.00011 seconds | ./spec/templates/helpers/markup/rdoc_markup_spec.rb[1:2:1] | passed | 0.0005 seconds | ./spec/templates/helpers/markup/rdoc_markup_spec.rb[1:3:1] | passed | 0.00017 seconds | ./spec/templates/helpers/markup/rdoc_markup_spec.rb[1:3:2] | passed | 0.00007 seconds | ./spec/templates/helpers/markup/rdoc_markup_spec.rb[1:3:3] | passed | 0.00007 seconds | ./spec/templates/helpers/markup/rdoc_markup_spec.rb[1:3:4] | passed | 0.00017 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:1:1] | passed | 0.00026 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:1:2] | passed | 0.00017 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:1:3] | passed | 0.00019 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:1:4] | passed | 0.00026 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:1:5] | passed | 0.0004 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:1:6] | passed | 0.00067 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:1:7] | passed | 0.00036 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:1:8] | passed | 0.00058 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:1:9] | passed | 0.00057 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:1:10] | passed | 0.00042 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:1] | passed | 0.0001 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:2] | passed | 0.00028 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:3] | passed | 0.00007 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:4] | passed | 0.00016 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:5] | passed | 0.00007 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:6] | passed | 0.00006 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:7] | passed | 0.00006 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:8] | passed | 0.00006 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:9] | passed | 0.00013 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:10] | passed | 0.00008 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:11] | passed | 0.00006 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:12] | passed | 0.00006 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:13] | passed | 0.00006 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:14] | passed | 0.00006 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:15] | passed | 0.00006 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:16] | passed | 0.00006 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:17] | passed | 0.00006 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:18] | passed | 0.00007 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:19] | passed | 0.00006 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:20] | passed | 0.00015 seconds | ./spec/templates/helpers/markup_helper_spec.rb[1:2:21] | passed | 0.00006 seconds | ./spec/templates/helpers/method_helper_spec.rb[1:1:1] | passed | 0.00099 seconds | ./spec/templates/helpers/method_helper_spec.rb[1:1:2] | passed | 0.00061 seconds | ./spec/templates/helpers/method_helper_spec.rb[1:1:3] | passed | 0.0012 seconds | ./spec/templates/helpers/method_helper_spec.rb[1:1:4] | passed | 0.00098 seconds | ./spec/templates/helpers/method_helper_spec.rb[1:2:1] | passed | 0.00069 seconds | ./spec/templates/helpers/method_helper_spec.rb[1:2:2] | passed | 0.00053 seconds | ./spec/templates/helpers/method_helper_spec.rb[1:2:3] | passed | 0.00092 seconds | ./spec/templates/helpers/method_helper_spec.rb[1:2:4] | passed | 0.00057 seconds | ./spec/templates/helpers/module_helper_spec.rb[1:1:1] | passed | 0.00122 seconds | ./spec/templates/helpers/module_helper_spec.rb[1:1:2] | passed | 0.00204 seconds | ./spec/templates/helpers/module_helper_spec.rb[1:1:3] | passed | 0.00111 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:1:1:1] | passed | 0.00082 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:1:1:2] | passed | 0.00072 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:1:1:3] | passed | 0.00071 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:1:1:4] | passed | 0.01551 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:1:1:5] | passed | 0.00121 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:1:1:6] | passed | 0.00076 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:1:1:7] | passed | 0.00078 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:1:1:8] | passed | 0.00087 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:1:1:9] | passed | 0.00108 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:1:1:10] | passed | 0.00124 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:1:1:11] | passed | 0.00185 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:1:1:12] | passed | 0.00078 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:1:1:13] | passed | 0.00133 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:1:1:14] | passed | 0.00164 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:1:1:15] | passed | 0.00243 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:2:1] | passed | 0.00053 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:2:2] | passed | 0.00012 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:3:1] | passed | 0.00023 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:3:2] | passed | 0.00058 seconds | ./spec/templates/helpers/text_helper_spec.rb[1:3:3] | passed | 0.0003 seconds | ./spec/templates/method_spec.rb[1:1:1:1] | passed | 0.01057 seconds | ./spec/templates/method_spec.rb[1:1:1:2] | passed | 0.01006 seconds | ./spec/templates/method_spec.rb[1:2:1:1] | passed | 0.00866 seconds | ./spec/templates/method_spec.rb[1:2:1:2] | passed | 0.00856 seconds | ./spec/templates/method_spec.rb[1:3:1:1] | passed | 0.01264 seconds | ./spec/templates/method_spec.rb[1:3:1:2] | passed | 0.01292 seconds | ./spec/templates/method_spec.rb[1:4:1:1] | passed | 0.00699 seconds | ./spec/templates/method_spec.rb[1:4:1:2] | passed | 0.00577 seconds | ./spec/templates/method_spec.rb[1:5:1:1] | passed | 0.01165 seconds | ./spec/templates/method_spec.rb[1:5:1:2] | passed | 0.01134 seconds | ./spec/templates/method_spec.rb[1:6:1:1] | passed | 0.00652 seconds | ./spec/templates/method_spec.rb[1:6:1:2] | passed | 0.00591 seconds | ./spec/templates/module_spec.rb[1:1] | passed | 0.07142 seconds | ./spec/templates/module_spec.rb[1:2] | passed | 0.0241 seconds | ./spec/templates/module_spec.rb[1:3] | passed | 0.02846 seconds | ./spec/templates/module_spec.rb[1:4] | passed | 0.02842 seconds | ./spec/templates/module_spec.rb[1:5] | passed | 0.02766 seconds | ./spec/templates/module_spec.rb[1:6] | passed | 0.04871 seconds | ./spec/templates/onefile_spec.rb[1:1] | passed | 0.04393 seconds | ./spec/templates/section_spec.rb[1:1:1] | passed | 0.00028 seconds | ./spec/templates/section_spec.rb[1:1:2] | passed | 0.00015 seconds | ./spec/templates/section_spec.rb[1:1:3] | passed | 0.0001 seconds | ./spec/templates/section_spec.rb[1:2:1] | passed | 0.00011 seconds | ./spec/templates/section_spec.rb[1:2:2] | passed | 0.00011 seconds | ./spec/templates/section_spec.rb[1:2:3] | passed | 0.00021 seconds | ./spec/templates/section_spec.rb[1:2:4] | passed | 0.00008 seconds | ./spec/templates/section_spec.rb[1:3:1] | passed | 0.00018 seconds | ./spec/templates/section_spec.rb[1:3:2] | passed | 0.0001 seconds | ./spec/templates/section_spec.rb[1:4:1] | passed | 0.00008 seconds | ./spec/templates/section_spec.rb[1:4:2] | passed | 0.00006 seconds | ./spec/templates/section_spec.rb[1:4:3] | passed | 0.00051 seconds | ./spec/templates/section_spec.rb[1:4:4] | passed | 0.00008 seconds | ./spec/templates/section_spec.rb[1:4:5] | passed | 0.00006 seconds | ./spec/templates/section_spec.rb[1:4:6] | passed | 0.00007 seconds | ./spec/templates/section_spec.rb[1:5:1] | passed | 0.00007 seconds | ./spec/templates/section_spec.rb[1:6:1] | passed | 0.00008 seconds | ./spec/templates/section_spec.rb[1:6:2] | passed | 0.00013 seconds | ./spec/templates/section_spec.rb[1:6:3] | passed | 0.00009 seconds | ./spec/templates/section_spec.rb[1:7:1] | passed | 0.00007 seconds | ./spec/templates/section_spec.rb[1:7:2] | passed | 0.00007 seconds | ./spec/templates/section_spec.rb[1:8:1] | passed | 0.00008 seconds | ./spec/templates/section_spec.rb[1:9:1] | passed | 0.00007 seconds | ./spec/templates/section_spec.rb[1:9:2] | passed | 0.00009 seconds | ./spec/templates/tag_spec.rb[1:1:1] | passed | 0.0063 seconds | ./spec/templates/tag_spec.rb[1:2:1] | passed | 0.00644 seconds | ./spec/templates/template_spec.rb[1:1:1] | passed | 0.00045 seconds | ./spec/templates/template_spec.rb[1:1:2] | passed | 0.00261 seconds | ./spec/templates/template_spec.rb[1:1:3] | passed | 0.00053 seconds | ./spec/templates/template_spec.rb[1:2:1] | passed | 0.0002 seconds | ./spec/templates/template_spec.rb[1:2:2] | passed | 0.00025 seconds | ./spec/templates/template_spec.rb[1:2:3] | passed | 0.00031 seconds | ./spec/templates/template_spec.rb[1:2:4] | passed | 0.0001 seconds | ./spec/templates/template_spec.rb[1:3:1] | passed | 0.00044 seconds | ./spec/templates/template_spec.rb[1:4:1] | passed | 0.00028 seconds | ./spec/templates/template_spec.rb[1:5:1] | passed | 0.00027 seconds | ./spec/templates/template_spec.rb[1:5:2] | passed | 0.00022 seconds | ./spec/templates/template_spec.rb[1:6:1] | passed | 0.00026 seconds | ./spec/templates/template_spec.rb[1:6:2] | passed | 0.00026 seconds | ./spec/templates/template_spec.rb[1:7:1] | passed | 0.00015 seconds | ./spec/templates/template_spec.rb[1:7:2] | passed | 0.0009 seconds | ./spec/templates/template_spec.rb[1:8:1] | passed | 0.00014 seconds | ./spec/templates/template_spec.rb[1:9:1] | passed | 0.00029 seconds | ./spec/templates/template_spec.rb[1:10:1] | passed | 0.00016 seconds | ./spec/templates/template_spec.rb[1:11:1] | passed | 0.00038 seconds | ./spec/templates/template_spec.rb[1:11:2] | passed | 0.00029 seconds | ./spec/templates/template_spec.rb[1:11:3] | passed | 0.00041 seconds | ./spec/templates/template_spec.rb[1:11:4] | passed | 0.0003 seconds | ./spec/templates/template_spec.rb[1:12:1] | passed | 0.00205 seconds | ./spec/templates/template_spec.rb[1:12:2] | passed | 0.00488 seconds | ./spec/templates/template_spec.rb[1:13:1] | passed | 0.0002 seconds | ./spec/templates/template_spec.rb[1:14:1] | passed | 0.00033 seconds | ./spec/templates/template_spec.rb[1:14:2] | passed | 0.00037 seconds | ./spec/templates/template_spec.rb[1:14:3] | passed | 0.00028 seconds | ./spec/templates/template_spec.rb[1:14:4] | passed | 0.00022 seconds | ./spec/templates/template_spec.rb[1:15:1] | passed | 0.00019 seconds | ./spec/templates/template_spec.rb[1:15:2] | passed | 0.00017 seconds | ./spec/templates/template_spec.rb[1:16:1] | passed | 0.00047 seconds | ./spec/templates/template_spec.rb[1:16:2] | passed | 0.00054 seconds | ./spec/templates/template_spec.rb[1:16:3] | passed | 0.00022 seconds | ./spec/templates/template_spec.rb[1:16:4] | passed | 0.00026 seconds | ./spec/templates/template_spec.rb[1:17:1] | passed | 0.00016 seconds | ./spec/templates/template_spec.rb[1:17:2] | passed | 0.0002 seconds | ./spec/templates/template_spec.rb[1:17:3] | passed | 0.00016 seconds | ./spec/templates/template_spec.rb[1:17:4] | passed | 0.00014 seconds | ./spec/templates/template_spec.rb[1:17:5] | passed | 0.00016 seconds | ./spec/templates/template_spec.rb[1:17:6] | passed | 0.00021 seconds | ./spec/templates/template_spec.rb[1:18:1] | passed | 0.00015 seconds | ./spec/templates/template_spec.rb[1:18:2] | passed | 0.00015 seconds | ./spec/templates/template_spec.rb[1:18:3] | passed | 0.00012 seconds | ./spec/templates/template_spec.rb[1:18:4] | passed | 0.00015 seconds | ./spec/verifier_spec.rb[1:1:1] | passed | 0.00019 seconds | ./spec/verifier_spec.rb[1:1:2] | passed | 0.00023 seconds | ./spec/verifier_spec.rb[1:1:3] | passed | 0.0002 seconds | ./spec/verifier_spec.rb[1:1:4] | passed | 0.00019 seconds | ./spec/verifier_spec.rb[1:1:5] | passed | 0.00025 seconds | ./spec/verifier_spec.rb[1:1:6] | passed | 0.00041 seconds | ./spec/verifier_spec.rb[1:1:7] | passed | 0.00079 seconds | ./spec/verifier_spec.rb[1:1:8] | passed | 0.00046 seconds | ./spec/verifier_spec.rb[1:2:1] | passed | 0.00025 seconds | ./spec/verifier_spec.rb[1:3:1] | passed | 0.00027 seconds | ./spec/verifier_spec.rb[1:3:2] | passed | 0.00018 seconds | ./spec/verifier_spec.rb[1:3:3] | passed | 0.00025 seconds | ./spec/verifier_spec.rb[1:4:1] | passed | 0.00012 seconds | ./spec/verifier_spec.rb[1:5:1] | passed | 0.0002 seconds | ./spec/verifier_spec.rb[1:6:1] | passed | 0.00025 seconds | yard-0.9.12/spec/core_ext/0000755000004100000410000000000013206751010015327 5ustar www-datawww-datayard-0.9.12/spec/core_ext/insertion_spec.rb0000755000004100000410000000213713206751010020706 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe Insertion do describe "#before" do it "places an object before another" do expect([1, 2].place(3).before(2)).to eq [1, 3, 2] expect([1, 2].place(3).before(1)).to eq [3, 1, 2] expect([1, [4], 2].place(3).before(2)).to eq [1, [4], 3, 2] end end describe "#after" do it "places an object after another" do expect([1, 2].place(3).after(2)).to eq [1, 2, 3] end it "no longer places an object after another and its subsections (0.6)" do expect([1, [2]].place(3).after(1)).to eq [1, 3, [2]] end it "places an array after an object" do expect([1, 2, 3].place([4]).after(1)).to eq [1, [4], 2, 3] end end describe "#before_any" do it "places an object before another anywhere inside list (including sublists)" do expect([1, 2, [3]].place(4).before_any(3)).to eq [1, 2, [4, 3]] end end describe "#after_any" do it "places an object after another anywhere inside list (including sublists)" do expect([1, 2, [3]].place(4).after_any(3)).to eq [1, 2, [3, 4]] end end end yard-0.9.12/spec/core_ext/module_spec.rb0000755000004100000410000000061013206751010020153 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe Module do describe "#class_name" do it "returns just the name of the class/module" do expect(YARD::CodeObjects::Base.class_name).to eq "Base" end end describe "#namespace" do it "returns everything before the class name" do expect(YARD::CodeObjects::Base.namespace_name).to eq "YARD::CodeObjects" end end end yard-0.9.12/spec/core_ext/symbol_hash_spec.rb0000755000004100000410000000436113206751010021205 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe SymbolHash do it "allows access to keys as String or Symbol" do h = SymbolHash.new(false) h['test'] = true expect(h[:test]).to be true expect(h['test']).to be true end describe "#delete" do it "accepts either Strings or Symbols as deletion key" do h = SymbolHash.new expect(h.keys.length).to eq 0 h['test'] = true expect(h.keys.length).to eq 1 h.delete(:test) expect(h.keys.length).to eq 0 h[:test] = true expect(h.keys.length).to eq 1 h.delete('test') expect(h.keys.length).to eq 0 end end describe "#key?" do it "returns same result for String or Symbol" do h = SymbolHash.new h[:test] = 1 expect(h.key?(:test)).to be true expect(h.has_key?('test')).to be true # rubocop:disable Style/PreferredHashMethods end end it "symbolizes 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") expect(h['test1']).to eq :hello expect(h['test2']).to eq "hello" end it "does not symbolize value if SymbolHash.new(false) is created" do h = SymbolHash.new(false) h['test'] = "hello" expect(h[:test]).to eq "hello" end it "does not symbolize value if it is not a String" do h = SymbolHash.new h['test'] = [1, 2, 3] expect(h['test']).to eq [1, 2, 3] end it "supports symbolization using #update or #merge!" do h = SymbolHash.new h.update('test' => 'value') expect(h[:test]).to eq :value h.merge!('test' => 'value2') # rubocop:disable Performance/RedundantMerge expect(h[:test]).to eq :value2 end it "supports symbolization non-destructively using #merge" do h = SymbolHash.new expect(h.merge('test' => 'value')[:test]).to eq :value expect(h).to eq SymbolHash.new end it "supports #initializing of a hash" do h = SymbolHash[:test => 1] expect(h[:test]).to eq 1 expect(h[:somethingelse]).to be nil end it "supports reverse merge syntax" do opts = {} opts = SymbolHash[ 'default' => 1 ].update(opts) expect(opts.keys).to eq [:default] expect(opts[:default]).to eq 1 end end yard-0.9.12/spec/core_ext/file_spec.rb0000755000004100000410000000440313206751010017611 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe File do describe ".relative_path" do it "returns the relative path between two files" do expect(File.relative_path('a/b/c/d.html', 'a/b/d/q.html')).to eq '../d/q.html' end it "returns the relative path between two directories" do expect(File.relative_path('a/b/c/d/', 'a/b/d/')).to eq '../d' end it "returns only the to file if from file is in the same directory as the to file" do expect(File.relative_path('a/b/c/d', 'a/b/c/e')).to eq 'e' end it "handles non-normalized paths" do expect(File.relative_path('Hello/./I/Am/Fred', 'Hello/Fred')).to eq '../../Fred' expect(File.relative_path('A//B/C', 'Q/X')).to eq '../../Q/X' end end describe ".cleanpath" do it "cleans double brackets" do expect(File.cleanpath('A//B/C')).to eq "A/B/C" end it "cleans a path with ." do expect(File.cleanpath('Hello/./I/.Am/Fred')).to eq "Hello/I/.Am/Fred" end it "cleans a path with .." do expect(File.cleanpath('Hello/../World')).to eq "World" end it "cleans a path with multiple .." do expect(File.cleanpath('A/B/C/../../D')).to eq "A/D" end it "cleans a path ending in .." do expect(File.cleanpath('A/B/C/D/..')).to eq "A/B/C" end it "allows '../' at the beginning if rel_root=true" do expect(File.cleanpath('A/../../B', true)).to eq '../B' end it "does not allow relative path above root" do expect(File.cleanpath('A/../../../../../D')).to eq "D" end it "does not remove multiple '../' at the beginning" do expect(File.cleanpath('../../A/B')).to eq 'A/B' end end describe ".open!" do it "creates the path before opening" do expect(File).to receive(:directory?).with('/path/to').and_return(false) expect(FileUtils).to receive(:mkdir_p).with('/path/to') expect(File).to receive(:open).with('/path/to/file', 'w') File.open!('/path/to/file', 'w') end it "just opens the file if the path exists" do expect(File).to receive(:directory?).with('/path/to').and_return(true) expect(FileUtils).not_to receive(:mkdir_p) expect(File).to receive(:open).with('/path/to/file', 'w') File.open!('/path/to/file', 'w') end end end yard-0.9.12/spec/core_ext/hash_spec.rb0000755000004100000410000000056213206751010017617 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe Hash do describe ".[]" do it "accepts an Array argument (Ruby 1.8.6 and older)" do list = [['foo', 'bar'], ['foo2', 'bar2']] expect(Hash[list]).to eq('foo' => 'bar', 'foo2' => 'bar2') end it "accepts an array as a key" do expect(Hash[['a', 'b'], 1]).to eq(['a', 'b'] => 1) end end end yard-0.9.12/spec/core_ext/string_spec.rb0000755000004100000410000000231213206751010020175 0ustar www-datawww-data# frozen_string_literal: true # described_in_docs String, '#camelcase' # described_in_docs String, '#underscore' RSpec.describe String do describe "#shell_split" do it "splits simple non-quoted text" do expect("a b c".shell_split).to eq %w(a b c) end it "splits double quoted text into single token" do expect('a "b c d" e'.shell_split).to eq ["a", "b c d", "e"] end it "splits single quoted text into single token" do expect("a 'b c d' e".shell_split).to eq ["a", "b c d", "e"] end it "handles escaped quotations in quotes" do expect("'a \\' b'".shell_split).to eq ["a ' b"] end it "handles escaped quotations outside quotes" do expect("\\'a 'b'".shell_split).to eq %w('a b) end it "handles escaped backslash" do expect("\\\\'a b c'".shell_split).to eq ['\a b c'] end it "handles any whitespace as space" do text = "foo\tbar\nbaz\r\nfoo2 bar2" expect(text.shell_split).to eq %w(foo bar baz foo2 bar2) end it "handles complex input" do text = "hello \\\"world \"1 2\\\" 3\" a 'b \"\\\\\\'' c" expect(text.shell_split).to eq ["hello", "\"world", "1 2\" 3", "a", "b \"\\'", "c"] end end end yard-0.9.12/spec/core_ext/array_spec.rb0000755000004100000410000000050713206751010020011 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe Array do describe "#place" do it "creates an Insertion object" do expect([].place('x')).to be_kind_of(Insertion) end it "allows multiple objects to be placed" do expect([1, 2].place('x', 'y', 'z').before(2)).to eq [1, 'x', 'y', 'z', 2] end end end yard-0.9.12/spec/logging_spec.rb0000755000004100000410000000260213206751010016507 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::Logger do describe "#show_backtraces" do it "is true if debug level is on" do log.show_backtraces = true log.enter_level(Logger::DEBUG) do log.show_backtraces = false expect(log.show_backtraces).to be true end expect(log.show_backtraces).to be false end end describe "#backtrace" do before { log.show_backtraces = true } after { log.show_backtraces = false } it "logs backtrace in error by default" do expect(log).to receive(:error).with("RuntimeError: foo") expect(log).to 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 "allows backtrace to be entered in other modes" do expect(log).to receive(:warn).with("RuntimeError: foo") expect(log).to 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 describe '#warn' do before { log.warned = false } after { log.warned = false } it 'changes #warned from false to true' do expect { log.warn('message') }.to change(log, :warned).from(false).to(true) end end end yard-0.9.12/spec/config_spec.rb0000755000004100000410000001752513206751010016340 0ustar www-datawww-data# frozen_string_literal: true require 'yaml' RSpec.describe YARD::Config do describe ".load" do before do expect(File).to receive(:file?).twice.with(CLI::Yardoc::DEFAULT_YARDOPTS_FILE).and_return(false) end it "uses default options if no ~/.yard/config is found" do expect(File).to receive(:file?).with(YARD::Config::IGNORED_PLUGINS).and_return(false) expect(File).to receive(:file?).with(YARD::Config::CONFIG_FILE).and_return(false) YARD::Config.load expect(YARD::Config.options).to eq YARD::Config::DEFAULT_CONFIG_OPTIONS end it "overwrites options with data in ~/.yard/config" do expect(File).to receive(:file?).with(YARD::Config::CONFIG_FILE).and_return(true) expect(File).to receive(:file?).with(YARD::Config::IGNORED_PLUGINS).and_return(false) expect(YAML).to receive(:load_file).with(YARD::Config::CONFIG_FILE).and_return('test' => true) YARD::Config.load expect(YARD::Config.options[:test]).to be true end it "ignores any plugins specified in '~/.yard/ignored_plugins'" do expect(File).to receive(:file?).with(YARD::Config::CONFIG_FILE).and_return(false) expect(File).to receive(:file?).with(YARD::Config::IGNORED_PLUGINS).and_return(true) expect(File).to receive(:read).with(YARD::Config::IGNORED_PLUGINS).and_return('yard-plugin plugin2') YARD::Config.load expect(YARD::Config.options[:ignored_plugins]).to eq ['yard-plugin', 'yard-plugin2'] expect(YARD::Config).not_to receive(:require).with('yard-plugin2') expect(YARD::Config.load_plugin('yard-plugin2')).to be false end it "loads safe_mode setting from --safe command line option" do expect(File).to receive(:file?).with(YARD::Config::IGNORED_PLUGINS).and_return(false) expect(File).to receive(:file?).with(YARD::Config::CONFIG_FILE).and_return(false) ARGV.replace(['--safe']) YARD::Config.load expect(YARD::Config.options[:safe_mode]).to be true ARGV.replace(['']) end end describe ".save" do it "saves options to config file" do allow(YARD::Config).to receive(:options).and_return(:a => 1, :b => %w(a b c)) file = double(:file) expect(File).to receive(:open).with(YARD::Config::CONFIG_FILE, 'w').and_yield(file) expect(file).to receive(:write).with(YAML.dump(:a => 1, :b => %w(a b c))) YARD::Config.save end end describe ".load_plugin" do it "loads a plugin by 'name' as 'yard-name'" do expect(YARD::Config).to receive(:require).with('yard-foo') expect(log).to receive(:debug).with(/Loading plugin 'yard-foo'/).once expect(YARD::Config.load_plugin('foo')).to be true end it "does not load plugins like 'doc-*'" do expect(YARD::Config).not_to receive(:require).with('yard-doc-core') YARD::Config.load_plugin('doc-core') YARD::Config.load_plugin('yard-doc-core') end it "loads plugin by 'yard-name' as 'yard-name'" do expect(YARD::Config).to receive(:require).with('yard-foo') expect(log).to receive(:debug).with(/Loading plugin 'yard-foo'/).once expect(YARD::Config.load_plugin('yard-foo')).to be true end it "loads plugin by 'yard_name' as 'yard_name'" do expect(YARD::Config).to receive(:require).with('yard_foo') expect(log).to receive(:debug).with(/Loading plugin 'yard_foo'/).once log.show_backtraces = false expect(YARD::Config.load_plugin('yard_foo')).to be true end it "logs error if plugin is not found" do expect(YARD::Config).to receive(:require).with('yard-foo').and_raise(LoadError) expect(log).to receive(:error).with(/Error loading plugin 'yard-foo'/).once expect(YARD::Config.load_plugin('yard-foo')).to be false end it "sanitizes plugin name (remove /'s)" do expect(YARD::Config).to receive(:require).with('yard-foofoo') expect(YARD::Config.load_plugin('foo/foo')).to be true end it "ignores plugins in :ignore_plugins" do allow(YARD::Config).to receive(:options).and_return(:ignored_plugins => ['yard-foo', 'yard-bar']) expect(YARD::Config.load_plugin('foo')).to be false expect(YARD::Config.load_plugin('bar')).to be false end end describe ".load_plugins" do it "loads gem plugins if :load_plugins is true" do allow(YARD::Config).to receive(:options).and_return(:load_plugins => true, :ignored_plugins => [], :autoload_plugins => []) allow(YARD::Config).to receive(:load_plugin) expect(YARD::Config).to receive(:require).with('rubygems') YARD::Config.load_plugins end it "ignores gem loading if RubyGems cannot load" do allow(YARD::Config).to receive(:options).and_return(:load_plugins => true, :ignored_plugins => [], :autoload_plugins => []) expect(YARD::Config).to receive(:require).with('rubygems').and_raise(LoadError) expect(YARD::Config.load_plugins).to be false end it "loads certain plugins automatically when specified in :autoload_plugins" do expect(File).to receive(:file?).with(CLI::Yardoc::DEFAULT_YARDOPTS_FILE).and_return(false) allow(YARD::Config).to receive(:options).and_return(:load_plugins => false, :ignored_plugins => [], :autoload_plugins => ['yard-plugin']) expect(YARD::Config).to receive(:require).with('yard-plugin').and_return(true) expect(YARD::Config.load_plugins).to be true end it "parses --plugin from command line arguments" do expect(YARD::Config).to receive(:arguments).at_least(1).times.and_return(%w(--plugin foo --plugin bar a b c)) expect(YARD::Config).to receive(:load_plugin).with('foo').and_return(true) expect(YARD::Config).to receive(:load_plugin).with('bar').and_return(true) expect(YARD::Config.load_plugins).to be true end it "loads --plugin arguments from .yardopts" do expect(File).to receive(:file?).with(CLI::Yardoc::DEFAULT_YARDOPTS_FILE).twice.and_return(true) expect(File).to receive(:file?).with(YARD::Config::CONFIG_FILE).and_return(false) expect(File).to receive(:file?).with(YARD::Config::IGNORED_PLUGINS).and_return(false) expect(File).to receive(:read_binary).with(CLI::Yardoc::DEFAULT_YARDOPTS_FILE).twice.and_return('--plugin foo') expect(YARD::Config).to receive(:load_plugin).with('foo') YARD::Config.load end it "loads any gem plugins starting with 'yard_' or 'yard-'" do expect(File).to receive(:file?).with(CLI::Yardoc::DEFAULT_YARDOPTS_FILE).and_return(false) allow(YARD::Config).to receive(:options).and_return(:load_plugins => true, :ignored_plugins => ['yard_plugin'], :autoload_plugins => []) plugins = { 'yard' => double('yard'), 'yard_plugin' => double('yard_plugin'), 'yard-plugin' => double('yard-plugin'), 'my-yard-plugin' => double('yard-plugin'), 'rspec' => double('rspec') } plugins.each do |k, v| expect(v).to receive(:name).at_least(1).times.and_return(k) end expect(YARD::GemIndex).to receive(:each) {|&b| plugins.values.each(&b) } expect(YARD::Config).to receive(:load_plugin).with('yard_plugin').and_return(false) expect(YARD::Config).to receive(:load_plugin).with('yard-plugin').and_return(true) expect(YARD::Config.load_plugins).to be true end it "logs an error if a gem raises an error" do allow(YARD::Config).to receive(:options).and_return(:load_plugins => true, :ignored_plugins => [], :autoload_plugins => []) plugins = { 'yard-plugin' => double('yard-plugin') } plugins.each do |k, v| expect(v).to receive(:name).at_least(1).times.and_return(k) end expect(YARD::GemIndex).to receive(:each) {|&b| plugins.values.each(&b) } expect(YARD::Config).to receive(:load_plugin).with('yard-plugin').and_raise(Gem::LoadError) expect(log).to receive(:error).with(/Error loading plugin 'yard-plugin'/) expect(YARD::Config.load_plugins).to be false end end end yard-0.9.12/spec/handlers/0000755000004100000410000000000013206751010015317 5ustar www-datawww-datayard-0.9.12/spec/handlers/module_handler_spec.rb0000755000004100000410000000176413206751010021653 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}ModuleHandler" do before(:all) { parse_file :module_handler_001, __FILE__ } it "parses a module block" do expect(Registry.at(:ModName)).not_to eq nil expect(Registry.at("ModName::OtherModName")).not_to eq nil end it "attaches docstring" do expect(Registry.at("ModName::OtherModName").docstring).to eq "Docstring" end it "handles any formatting" do expect(Registry.at(:StressTest)).not_to eq nil end it "handles complex module names" do expect(Registry.at("A::B")).not_to eq nil end it "handles modules in the form ::ModName" do expect(Registry.at("Kernel")).not_to be nil end it "lists mixins in proper order" do expect(Registry.at('D').mixins).to eq [P(:C), P(:B), P(:A)] end it "creates proper module when constant is in namespace" do expect(Registry.at('Q::FOO::A')).not_to be nil end end yard-0.9.12/spec/handlers/examples/0000755000004100000410000000000013206751010017135 5ustar www-datawww-datayard-0.9.12/spec/handlers/examples/visibility_handler_001.rb.txt0000755000004100000410000000063313206751010024551 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 def decpriv; end private class Bar; end module Baz; end private :not_exist! endyard-0.9.12/spec/handlers/examples/attribute_handler_001.rb.txt0000755000004100000410000000055013206751010024363 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.9.12/spec/handlers/examples/class_condition_handler_001.rb.txt0000755000004100000410000000131313206751010025531 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.9.12/spec/handlers/examples/exception_handler_001.rb.txt0000755000004100000410000000170513206751010024361 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.9.12/spec/handlers/examples/module_handler_001.rb.txt0000755000004100000410000000050313206751010023643 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.9.12/spec/handlers/examples/process_handler_001.rb.txt0000755000004100000410000000026213206751010024036 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.9.12/spec/handlers/examples/method_handler_001.rb.txt0000755000004100000410000000364013206751010023643 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; def d_splat(reg, **opts); end def d_unnamed_splat(**); 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.9.12/spec/handlers/examples/class_handler_001.rb.txt0000755000004100000410000000374713206751010023500 0ustar www-datawww-data# Docstring class A module B; end private class B::C < String; def method1; end def method2; end end class X :instance} } let(:class_name) { 'DecoratorTest' } let(:docstring) { 'the foo method' } let(:param_string) { 'def foo param1, param2; end' } let(:method_defs) { [] } let(:method_string) { "#{class_name}#foo" } let(:code) do <<-eof class #{class_name} #{make_defs(*method_defs)} # #{docstring} mock_decorator #{param_string} end eof end before do Registry.clear YARD::Handlers::Base.clear_subclasses create_test_handler :mock create_test_handler :first create_test_handler :second create_test_handler :third StubbedSourceParser.parse_string code end it "returns an array of hashes containing the method proxy, node, and name" do expect(subject[:return]).to be_an Array expect(subject[:return].first[:name].to_s).to eq 'foo' expect(subject[:return].first[:method].to_s).to eq method_string expect(subject[:return].first[:node]).to be_a YARD::Parser::Ruby::AstNode end describe "method is a MethodObject if the method has been defined" do let(:code) { "class DecoratorTest; mock_decorator def foo; end; end" } specify do expect(subject[:return].first[:method]). to be_a YARD::CodeObjects::MethodObject end end describe "method is a Proxy if the method has not been defined" do let(:code) { "class DecoratorTest; mock_decorator :foo; end" } specify do expect(subject[:return].first[:method]).to be_a YARD::CodeObjects::Proxy end end specify "block yields method proxy, node, name" do expect(subject[:name]).to be_a Symbol expect(subject[:name]).to eq :foo expect(subject[:method]).to be_a YARD::CodeObjects::MethodObject expect(subject[:method].to_s).to eq method_string expect(subject[:node]).to be_a YARD::Parser::Ruby::AstNode end describe "capitalized method names" do let(:method_defs) { [:Foo] } let(:param_string) { 'def Foo param1, param2; end' } specify do expect(subject[:method].to_s).to eq "#{class_name}#Foo" end end describe "nodes argument" do subject { data[:mock][:return].map {|h| h[:method].to_s } } describe "assumes all params refer to methods by default" do let(:method_defs) { [:foo, :bar] } let(:param_string) { method_defs.map(&:inspect).join(',') } let(:nodes) { [] } specify do expect(subject).to eq ["#{class_name}#foo", "#{class_name}#bar"] end end describe "can specify which params to capture as methods" do let(:method_defs) { [:foo, :bar, :baz, :bat] } let(:parameters) do [:option_1, :baz, :bat, :option_2, :foo, :bar].map do |s| make_ast s.inspect end end describe "as a single param" do let(:nodes) { parameters[4] } specify do expect(subject).to eq ["#{class_name}#foo"] end end describe "as a list of params" do let(:nodes) { [parameters[4], parameters[5]] } specify do expect(subject).to eq ["#{class_name}#foo", "#{class_name}#bar"] end end describe "as a range" do let(:nodes) { parameters[4..-1] } specify do expect(subject).to eq ["#{class_name}#foo", "#{class_name}#bar"] end end describe "as multiple ranges" do # Written like this due to Ruby 1.8. Can also splat the ranges as # separate params: # *parameters[1..2], *parameters[4..-1] let(:nodes) { parameters[1..2] + parameters[4..-1] } specify do expect(subject).to eq [ "#{class_name}#baz", "#{class_name}#bat", "#{class_name}#foo", "#{class_name}#bar" ] end end end describe "can select no nodes by passing nil" do let(:nodes) { [nil] } specify do expect(subject).to eq [] end end end describe "scope option" do describe "defaults to :instance" do let(:mock_handler_opts) { {} } specify do expect(subject[:return].first[:method].to_s).to eq method_string end end describe "creates method proxies" do shared_examples "decorator helper scope" do let(:param_string) { decorator_params.map(&:inspect).join(',') } describe "for symbols" do let(:decorator_params) { [:foo, :bar] } specify do expect(subject.count).to eq decorator_params.count subject.each_with_index do |_, i| expect(subject[i]).to be_a YARD::CodeObjects::MethodObject expect(subject[i].to_s).to eq \ "#{class_name}#{mock_handler_opts[:scope] == :class ? '.' : '#'}#{decorator_params[i]}" end end end describe "for string literals" do let(:decorator_params) { ['foo', 'bar'] } specify do expect(subject.count).to eq decorator_params.count subject.each_with_index do |_, i| expect(subject[i]).to be_a YARD::CodeObjects::MethodObject expect(subject[i].to_s).to eq \ "#{class_name}#{mock_handler_opts[:scope] == :class ? '.' : '#'}#{decorator_params[i]}" end end end describe "for methods" do let(:param_string) { decorator_params.join(',') } let(:decorator_params) do ["def #{'self.' if mock_handler_opts[:scope] == :class}foo f1, f2; end", "def #{'self.' if mock_handler_opts[:scope] == :class}bar b1, b2; end"] end specify do expect(subject.count).to eq decorator_params.count subject.each_with_index do |_, i| expect(subject[i]).to be_a YARD::CodeObjects::MethodObject expect(subject[i].to_s).to eq \ class_name + (mock_handler_opts[:scope] == :class ? '.' : '#') + decorator_params[i].split(' ')[1][/\w+$/] end end end end # decorator helper scope shared examples subject { data[:mock][:return].map {|h| h[:method] } } let(:docstring) { 'the foo method' } let(:method_defs) { [:foo, :bar] } describe "for :instance" do let(:mock_handler_opts) { {:scope => :instance} } include_examples "decorator helper scope" end describe "for :class" do let(:mock_handler_opts) { {:scope => :class} } include_examples "decorator helper scope" end end end describe "docstring from decorator" do subject { Registry.at method_string } specify "attaches to method definitions as decorator parameters" do expect(subject.docstring).to eq docstring end describe "does not attach" do describe "to undefined methods" do let(:code) do <<-eof class #{class_name} # #{docstring} mock_decorator :foo end eof end specify do expect(subject).not_to respond_to :docstring end end describe "to methods with existing docstring" do let(:code) do <<-eof class #{class_name} # original docstring def foo; end # #{docstring} mock_decorator :foo end eof end specify do expect(subject.docstring).to eq 'original docstring' end end end end describe "chained decorators" do subject { Registry.at method_string } let(:param_string) { 'def foo param1, param2; end' } let(:code) do <<-eof class #{class_name} #{make_defs(*method_defs)} # #{docstring} first_decorator second_decorator third_decorator #{param_string} end eof end specify "register nested method defs" do expect(subject).to be_a YARD::CodeObjects::MethodObject end describe "transfer docstring to decorated method defs" do specify do expect(subject.docstring).to eq docstring end describe "unless opt-out param is set" do let(:mock_handler_opts) { {:transfer_docstring => false} } specify do expect(subject.docstring.empty?).to be true end end end describe "don't transfer docstring to referenced methods" do let(:method_defs) { [:foo] } let(:param_string) { ':foo' } specify do expect(subject.docstring.empty?).to be true end end specify "don't transfer docstring to other decorators" do expect(Registry.at("#{class_name}#second_decorator")). not_to respond_to :docstring expect(Registry.at("#{class_name}#third_decorator")). not_to respond_to :docstring end describe "transfer source to decorated method defs" do specify do expect(subject.source).to eq code.lines.to_a[-2].strip end describe "unless opt-out param is set" do let(:mock_handler_opts) { {:transfer_source => false} } specify do expect(subject.source).to eq param_string end end end describe "don't transfer source to referenced methods" do let(:method_defs) { [:foo] } let(:param_string) { ':foo' } specify do expect(subject.source).to eq make_defs(*method_defs) end end end end # process_decorator end unless LEGACY_PARSER yard-0.9.12/spec/handlers/class_variable_handler_spec.rb0000755000004100000410000000067313206751010023336 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}ClassVariableHandler" do before(:all) { parse_file :class_variable_handler_001, __FILE__ } it "does not parse class variables inside methods" do obj = Registry.at("A::B::@@somevar") expect(obj.source).to eq "@@somevar = \"hello\"" expect(obj.value).to eq '"hello"' end end yard-0.9.12/spec/handlers/processor_spec.rb0000755000004100000410000000204213206751010020676 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe YARD::Handlers::Processor do before do @proc = Handlers::Processor.new(OpenStruct.new(:parser_type => :ruby)) end it "starts with public visibility" do expect(@proc.visibility).to eq :public end it "starts in instance scope" do expect(@proc.scope).to eq :instance end it "starts in root namespace" do expect(@proc.namespace).to eq Registry.root end it "has a globals structure" do expect(@proc.globals).to be_a(OpenStruct) end it "ignores HandlerAborted exceptions (but print debug info)" do class AbortHandlerProcessor < YARD::Handlers::Ruby::Base process { abort! } end stmt = OpenStruct.new(:line => 1, :show => 'SOURCE') allow(@proc).to receive(:find_handlers).and_return([AbortHandlerProcessor]) expect(log).to receive(:debug).with(/AbortHandlerProcessor cancelled from/) expect(log).to receive(:debug).with("\tin file '(stdin)':1:\n\nSOURCE\n") @proc.process([stmt]) end end yard-0.9.12/spec/handlers/alias_handler_spec.rb0000755000004100000410000000540213206751010021450 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}AliasHandler" do before(:all) { parse_file :alias_handler_001, __FILE__ } it "throws alias into namespace object list" do expect(P(:A).aliases[P("A#b")]).to eq :a end ['c', 'd?', '[]', '[]=', '-@', '%', '*', 'cstrkey', 'cstrmeth'].each do |a| it "handles the Ruby 'alias' keyword syntax for method ##{a}" do expect(P('A#' + a)).to be_instance_of(CodeObjects::MethodObject) expect(P('A#' + a).is_alias?).to be true end end it "handles keywords as the alias name" do expect(P('A#for')).to be_instance_of(CodeObjects::MethodObject) end it "allows ConstantNames to be specified as aliases" do expect(P('A#ConstantName')).to be_instance_of(CodeObjects::MethodObject) end it "creates a new method object for the alias" do expect(P("A#b")).to be_instance_of(CodeObjects::MethodObject) end it "pulls the method into the current class if it's from another one" do expect(P(:B).aliases[P("B#q")]).to eq :x expect(P(:B).aliases[P("B#r?")]).to eq :x end it "gracefully fails to pull a method in if the original method cannot be found" do expect(P(:B).aliases[P("B#s")]).to eq :to_s end it "allows complex Ruby expressions after the alias parameters" do expect(P(:B).aliases[P("B#t")]).to eq :inspect end it "shows up in #is_alias? for method" do expect(P("B#t").is_alias?).to be true expect(P('B#r?').is_alias?).to be true end it "allows operators and keywords to be specified as symbols" do expect(P('B#<<')).to be_instance_of(CodeObjects::MethodObject) expect(P('B#for')).to be_instance_of(CodeObjects::MethodObject) end it "handles keywords in alias names" do expect(P('B#do').is_alias?).to be true expect(P('B#x2').is_alias?).to be true expect(P(:B).aliases[P('B#do')]).to eq :x expect(P(:B).aliases[P('B#x2')]).to eq :do end it "handles quoted symbols" do foo = Registry.at('A#foo') expect(foo).not_to be nil expect(foo.is_alias?).to be true expect(Registry.at('A').aliases[foo]).to eq :a end it "prepends aliases object's docstring to comments" do expect(Registry.at('D#a').tag(:return).types).to eq ['Numeric'] expect(Registry.at('D#b').tag(:return).types).to eq ['String'] expect(Registry.at('D#b').docstring).to eq "Foo bar" end it "raises an UndocumentableError if only one parameter is passed" do undoc_error "alias_method :q" end it "raises 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.9.12/spec/handlers/constant_handler_spec.rb0000755000004100000410000000676113206751010022221 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}ConstantHandler" do before(:all) { parse_file :constant_handler_001, __FILE__ } it "does not parse constants inside methods" do expect(Registry.at("A::B::SOMECONSTANT").source).to eq "SOMECONSTANT= \"hello\"" end it "only parses valid constants" do expect(Registry.at("A::B::notaconstant")).to be nil end it "maintains newlines" do expect(Registry.at("A::B::MYCONSTANT").value.delete("\r")).to eq "A +\nB +\nC +\nD" end it "turns Const = Struct.new(:sym) into class Const with attr :sym" do obj = Registry.at("MyClass") expect(obj).to be_kind_of(CodeObjects::ClassObject) attrs = obj.attributes[:instance] [:a, :b, :c].each do |key| expect(attrs).to have_key(key) expect(attrs[key][:read]).not_to be nil expect(attrs[key][:write]).not_to be nil end end it 'documents block for Struct.new if present' do obj = Registry.at("MyStructWithConstant") expect(obj).to be_kind_of(CodeObjects::ClassObject) expect(obj.constants[0].docstring).to eq 'A constant.' expect(obj.constants[0].name).to eq :CONSTANT expect(obj.constants[0].value).to eq "42" end it "turns Const = Struct.new('Name', :sym) into class Const with attr :sym" do obj = Registry.at("NotMyClass") expect(obj).to be_kind_of(CodeObjects::ClassObject) attrs = obj.attributes[:instance] [:b, :c].each do |key| expect(attrs).to have_key(key) expect(attrs[key][:read]).not_to be nil expect(attrs[key][:write]).not_to be nil end expect(Registry.at("NotMyClass2")).to be nil end it "turns Const = Struct.new into empty struct" do obj = Registry.at("MyEmptyStruct") expect(obj).not_to be nil expect(obj.attributes[:instance]).to be_empty end it "maintains docstrings on structs defined via constants" do obj = Registry.at("DocstringStruct") expect(obj).not_to be nil expect(obj.docstring).to eq "A crazy struct." expect(obj.attributes[:instance]).not_to be_empty a1 = Registry.at("DocstringStruct#bar") a2 = Registry.at("DocstringStruct#baz") expect(a1.docstring).to eq "An attr" expect(a1.tag(:return).types).to eq ["String"] expect(a2.docstring).to eq "Another attr" expect(a2.tag(:return).types).to eq ["Number"] a3 = Registry.at("DocstringStruct#new_syntax") expect(a3.docstring).to eq "Attribute defined with the new syntax" expect(a3.tag(:return).types).to eq ["Symbol"] end it "raises undocumentable error in 1.9 parser for Struct.new assignment to non-const" do undoc_error "nonconst = Struct.new" end unless LEGACY_PARSER %w(module class).each do |type| it "does not allow #{type} to be redefined as constant" do undoc_error <<-eof #{type} Foo; end Foo = "value" eof end end unless LEGACY_PARSER it "allows constant to have same name as constant in parent namespace" do YARD.parse_string <<-eof module A class C; end module B; C = 1 end end eof expect(log.io.string).to eq "" expect(Registry.at('A::B::C').type).to eq :constant end it "detects compound constant names" do YARD.parse_string <<-eof module A class AA; end AA::B = true end A::AA::C = true eof expect(Registry.at('A::AA::B').type).to eq :constant expect(Registry.at('A::AA::C').type).to eq :constant end if HAVE_RIPPER end yard-0.9.12/spec/handlers/visibility_handler_spec.rb0000755000004100000410000000312513206751010022546 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}VisibilityHandler" do before(:all) { parse_file :visibility_handler_001, __FILE__ } it "is able to set visibility to public" do expect(Registry.at("Testing#pub").visibility).to eq :public expect(Registry.at("Testing#pub2").visibility).to eq :public end it "is able to set visibility to private" do expect(Registry.at("Testing#priv").visibility).to eq :private end it "is able to set visibility to protected" do expect(Registry.at("Testing#prot").visibility).to eq :protected end it "supports parameters and only set visibility on those methods" do expect(Registry.at('Testing#notpriv').visibility).to eq :protected expect(Registry.at('Testing#notpriv2').visibility).to eq :protected expect(Registry.at('Testing#notpriv?').visibility).to eq :protected end it "only accepts strings and symbols" do expect(Registry.at('Testing#name')).to be nil expect(Registry.at('Testing#argument')).to be nil expect(Registry.at('Testing#method_call')).to be nil end it "handles constants passed in as symbols" do expect(Registry.at('Testing#Foo').visibility).to eq :private end it "does not register classes with visibility" do expect(Registry.at('Testing::Bar').visibility).to eq :public expect(Registry.at('Testing::Baz').visibility).to eq :public end it "can decorate a method definition" do expect(Registry.at('Testing#decpriv').visibility).to eq :private end unless LEGACY_PARSER end yard-0.9.12/spec/handlers/base_spec.rb0000755000004100000410000001542013206751010017575 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' require 'ostruct' include Parser RSpec.describe YARD::Handlers::Base do describe "#handles and inheritance" do before do allow(Handlers::Base).to receive(:inherited) end it "keeps track of subclasses" do expect(Handlers::Base).to receive(:inherited).once class TestHandler < Handlers::Base; end end it "raises NotImplementedError if process is called on a class with no #process" do class TestNotImplementedHandler < Handlers::Base end expect { TestNotImplementedHandler.new(0, 0).process }.to raise_error(NotImplementedError) end it "allows multiple handles arguments" do expect(Handlers::Base).to receive(:inherited).once class TestHandler1 < Handlers::Base handles :a, :b, :c end expect(TestHandler1.handlers).to eq [:a, :b, :c] end it "allows multiple handles calls" do expect(Handlers::Base).to receive(:inherited).once class TestHandler2 < Handlers::Base handles :a handles :b handles :c end expect(TestHandler2.handlers).to eq [:a, :b, :c] end end describe "#abort! (and HandlerAborted)" do it "allows HandlerAborted to be raised" do class AbortHandler1 < Handlers::Ruby::Base process { abort! } end expect { AbortHandler1.new(nil, nil).process }.to raise_error(HandlerAborted) end end describe "transitive tags" do it "adds 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 expect(Registry.at('A').tag(:since).text).to eq "1.0" expect(Registry.at('A#foo').tag(:since).text).to eq "1.0" expect(Registry.at('A#bar').tag(:since).text).to eq "1.1" expect(Registry.at('A#bar').tag(:author)).to be nil end end describe "sharing global state" do it "allows 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' expect(GlobalStateHandler1.state).to eq nil expect(GlobalStateHandler2.state).to eq :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 "pushes and return all old state info after block" do class PushStateHandler1 < Handlers::Base include RSpec::Matchers RSpec::Expectations::Syntax.enable_expect(self) def process push_state(:namespace => "FOO", :scope => :class, :owner => "BAR") do expect(namespace).to eq "FOO" expect(scope).to eq :class expect(owner).to eq "BAR" end expect(namespace).to eq "ROOT" expect(owner).to eq "ROOT" expect(scope).to eq :instance end end process PushStateHandler1 end it "allows owner to be pushed individually" do class PushStateHandler2 < Handlers::Base include RSpec::Matchers RSpec::Expectations::Syntax.enable_expect(self) def process push_state(:owner => "BAR") do expect(namespace).to eq "ROOT" expect(scope).to eq :instance expect(owner).to eq "BAR" end expect(owner).to eq "ROOT" end end process PushStateHandler2 end it "allows scope to be pushed individually" do class PushStateHandler3 < Handlers::Base include RSpec::Matchers RSpec::Expectations::Syntax.enable_expect(self) def process push_state(:scope => :foo) do expect(namespace).to eq "ROOT" expect(scope).to eq :foo expect(owner).to eq "ROOT" end expect(scope).to eq :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, __FILE__, __LINE__ + 1) 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 expect(Registry.at('#FOO')).to be nil create_handler(stmts, parser_type) parse(file, parser_type) expect(Registry.at('#FOO')).send(creates ? :not_to : :to, 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 "allows handler to be specific to a file" do test_handler 'file_a.rb', 'in_file "file_a.rb"', true, parser_type end it "ignores handler if filename does not match" do test_handler 'file_b.rb', 'in_file "file_a.rb"', false, parser_type end it "only tests 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 "tests exact match for entire String" do test_handler 'file_a.rb', 'in_file "file"', false, parser_type end it "allows 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 "allows 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.9.12/spec/handlers/legacy_base_spec.rb0000755000004100000410000001057113206751010021123 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' include Parser::Ruby::Legacy RSpec.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 "returns the String's value without quotes" do expect(tokval('"hello"')).to eq "hello" end it "does not allow interpolated strings with TkSTRING" do expect(tokval('"#{c}"', RubyToken::TkSTRING)).to be nil end it "returns a Symbol's value as a String (as if it was done via :name.to_sym)" do expect(tokval(':sym')).to eq :sym end it "returns nil for any non accepted type" do expect(tokval('identifier')).to be nil expect(tokval(':sym', RubyToken::TkId)).to be nil end it "accepts TkVal tokens by default" do expect(tokval('2.5')).to eq 2.5 expect(tokval(':sym')).to eq :sym end it "accepts any ID type if TkId is set" do expect(tokval('variable', RubyToken::TkId)).to eq "variable" expect(tokval('CONSTANT', RubyToken::TkId)).to eq "CONSTANT" end it "allows extra token types to be accepted" do expect(tokval('2.5', RubyToken::TkFLOAT)).to eq 2.5 expect(tokval('2', RubyToken::TkFLOAT)).to be nil expect(tokval(':symbol', RubyToken::TkFLOAT)).to be nil end it "allows :string for any string type" do expect(tokval('"hello"', :string)).to eq "hello" expect(tokval('"#{c}"', :string)).to eq '#{c}' end it "does not include interpolated strings when using :attr" do expect(tokval('"#{c}"', :attr)).to be nil end it "allows any number type with :number" do expect(tokval('2.5', :number)).to eq 2.5 expect(tokval('2', :number)).to eq 2 end it "allows method names with :identifier" do expect(tokval('methodname?', :identifier)).to eq "methodname?" end # it "obeys documentation expectations" do docspec end end RSpec.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 "returns the list of tokvalues" do expect(tokval_list(":a, :b, \"\#{c}\", 'd'", :attr)).to eq [:a, :b, 'd'] expect(tokval_list(":a, :b, File.read(\"\#{c}\", ['w']), :d", RubyToken::Token)).to eq [:a, :b, 'File.read("#{c}", [\'w\'])', :d] end it "tries to skip any invalid tokens" do expect(tokval_list(":a, :b, \"\#{c}\", :d", :attr)).to eq [:a, :b, :d] expect(tokval_list(":a, :b, File.read(\"\#{c}\", 'w', File.open { }), :d", :attr)).to eq [:a, :b, :d] expect(tokval_list("CONST1, identifier, File.read(\"\#{c}\", 'w', File.open { }), CONST2", RubyToken::TkId)).to eq ['CONST1', 'identifier', 'CONST2'] end it "ignores a token if another invalid token is read before a comma" do expect(tokval_list(":a, :b XYZ, :c", RubyToken::TkSYMBOL)).to eq [:a, :c] end it "stops on most keywords" do expect(tokval_list(':a rescue :x == 5', RubyToken::Token)).to eq [:a] end it "handles ignore parentheses that begin the token list" do expect(tokval_list('(:a, :b, :c)', :attr)).to eq [:a, :b, :c] end it "ends when a closing parenthesis was found" do expect(tokval_list(':a, :b, :c), :d', :attr)).to eq [:a, :b, :c] end it "ignores parentheses around items in a list" do expect(tokval_list(':a, (:b), :c, (:d TEST), :e, [:f], :g', :attr)).to eq [:a, :b, :c, :e, :g] expect(tokval_list(':a, (((:f)))', :attr)).to eq [:a, :f] expect(tokval_list(':a, ([:f]), :c)', RubyToken::Token)).to eq [:a, '[:f]', :c] end it "does not stop on a true/false/self keyword (cannot handle nil)" do expect(tokval_list(':a, true, :b, self, false, :c, nil, File, super, if, XYZ', RubyToken::Token)).to eq [:a, true, :b, 'self', false, :c, 'File', 'super'] end it "ignores invalid commas" do expect(tokval_list(":a, :b, , :d")).to eq [:a, :b, :d] end it "returns an empty list if no matches were found" do expect(tokval_list('attr_accessor :x')).to eq [] end it "treats {} 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. expect(tokval_list("opts = {}", :all)).to eq ["opts={}"] end end yard-0.9.12/spec/handlers/mixin_handler_spec.rb0000755000004100000410000000364213206751010021507 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}MixinHandler" do before(:all) { parse_file :mixin_handler_001, __FILE__ } it "handles includes from classes or modules" do expect(Registry.at(:X).instance_mixins).to include(P(:A)) expect(Registry.at(:Y).instance_mixins).to include(P(:A)) end it "handles includes in class << self" do expect(Registry.at(:Y).class_mixins).to include(P(:A)) end it "handles includes for modules that don't yet exist" do expect(Registry.at(:X).instance_mixins).to include(P(nil, :NOTEXIST)) end it "sets the type of non-existing modules to :module" do o = Registry.at(:X).instance_mixins.find {|obj| obj.name == :NOTEXIST } expect(o.type).to eq :module end it "handles includes with multiple parameters" do expect(Registry.at(:X)).not_to be nil end it "handles complex include statements" do expect(P(:Y).instance_mixins).to include(P('B::C')) expect(P(:Y).instance_mixins).to include(P(:B)) end it "treats a mixed in Constant by taking its value as the real object name" do expect(P(:Y).instance_mixins).to include(Registry.at('B::D')) end it "adds includes in the correct order when include is given multiple arguments" do expect(P(:Z).instance_mixins).to eq [P(:A), P(:B)] end it "avoids including self for unresolved mixins of the same name" do expect(P("ABC::DEF::FOO").mixins).to eq [P("ABC::FOO")] expect(P("ABC::DEF::BAR").mixins).to eq [P("ABC::BAR")] end it "raises undocumentable error if argument is variable" do undoc_error "module X; include invalid; end" expect(Registry.at('X').mixins).to eq [] end it "parses all other arguments before erroring out on undocumentable error" do undoc_error "module X; include invalid, Y; end" expect(Registry.at('X').mixins).to eq [P('Y')] end end yard-0.9.12/spec/handlers/exception_handler_spec.rb0000755000004100000410000000322513206751010022356 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}ExceptionHandler" do before(:all) { parse_file :exception_handler_001, __FILE__ } it "does not document an exception outside of a method" do expect(P('Testing').has_tag?(:raise)).to be false end it "documents a valid raise" do expect(P('Testing#mymethod').tag(:raise).types).to eq ['ArgumentError'] end it "only documents non-dynamic raises" do expect(P('Testing#mymethod2').tag(:raise)).to be nil expect(P('Testing#mymethod6').tag(:raise)).to be nil expect(P('Testing#mymethod7').tag(:raise)).to be nil end it "treats ConstantName.new as a valid exception class" do expect(P('Testing#mymethod8').tag(:raise).types).to eq ['ExceptionClass'] end it "does not document a method with an existing @raise tag" do expect(P('Testing#mymethod3').tag(:raise).types).to eq ['A'] end it "only documents the first raise message of a method (limitation of exception handler)" do expect(P('Testing#mymethod4').tag(:raise).types).to eq ['A'] end it "handles complex class names" do expect(P('Testing#mymethod5').tag(:raise).types).to eq ['YARD::Parser::UndocumentableError'] end it "ignores any raise calls on a receiver" do expect(P('Testing#mymethod9').tag(:raise)).to be nil end it "handles raise expressions that are method calls" do expect(P('Testing#mymethod10').tag(:raise)).to be nil expect(P('Testing#mymethod11').tag(:raise)).to be nil end it "ignores empty raise call" do expect(P('Testing#mymethod12').tag(:raise)).to be nil end end yard-0.9.12/spec/handlers/method_handler_spec.rb0000755000004100000410000001430613206751010021642 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.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 "adds methods to parent's #meths list" do expect(P(:Foo).meths).to include(P("Foo#method1")) end it "parses and adds class methods (self.method2)" do expect(P(:Foo).meths).to include(P("Foo.method2")) end it "parses and adds class methods from other namespaces (String.hello)" do expect(P("String.hello")).to be_instance_of(CodeObjects::MethodObject) end [:[], :[]=, :allowed?, :/, :=~, :==, :`, :|, :*, :&, :%, :'^', :-@, :+@, :'~@'].each do |name| it "allows valid method #{name}" do expect(Registry.at("Foo##{name}")).not_to be nil end end it "allows self.methname" do expect(Registry.at("Foo.new")).not_to be nil end it "marks dynamic methods as such" do expect(P('Foo#dynamic').dynamic?).to be true end it "shows that a method is explicitly defined (if it was originally defined implicitly by attribute)" do expect(P('Foo#method1').is_explicit?).to be true end it "handles parameters" do expect(P('Foo#[]').parameters).to eq [['key', "'default'"]] expect(P('Foo#/').parameters).to eq [['x', "File.new('x', 'w')"], ['y', '2']] end it "handles opts = {} as parameter" do expect(P('Foo#optsmeth').parameters).to eq [['x', nil], ['opts', '{}']] end it "handles &block as parameter" do expect(P('Foo#blockmeth').parameters).to eq [['x', nil], ['&block', nil]] end it "handles double splats" do expect(P('Foo#d_splat').parameters).to eq [["reg", nil], ["**opts", nil]] expect(P('Foo#d_unnamed_splat').parameters).to eq [] end it "handles overloads" do meth = P('Foo#foo') o1 = meth.tags(:overload).first expect(o1.name).to eq :bar expect(o1.parameters).to eq [['a', nil], ['b', "1"]] expect(o1.tag(:return).type).to eq "String" o2 = meth.tags(:overload)[1] expect(o2.name).to eq :baz expect(o2.parameters).to eq [['b', nil], ['c', nil]] expect(o2.tag(:return).type).to eq "Fixnum" o3 = meth.tags(:overload)[2] expect(o3.name).to eq :bang expect(o3.parameters).to eq [['d', nil], ['e', nil]] expect(o3.docstring).to be_empty expect(o3.docstring).to be_blank end it "sets a return tag if not set on #initialize" do meth = P('Foo#initialize') expect(meth).to have_tag(:return) expect(meth.tag(:return).types).to eq ["Foo"] expect(meth.tag(:return).text).to eq "a new instance of Foo" end %w(inherited included method_added method_removed method_undefined).each do |meth| it "sets @private tag on #{meth} callback method if no docstring is set" do expect(P('Foo.' + meth)).to have_tag(:private) end end it "does not set @private tag on extended callback method since docstring is set" do expect(P('Foo.extended')).not_to have_tag(:private) end it "adds @return [Boolean] tag to methods ending in ? without return types" do meth = P('Foo#boolean?') expect(meth).to have_tag(:return) expect(meth.tag(:return).types).to eq ['Boolean'] end it "adds Boolean type to return tag without types" do meth = P('Foo#boolean2?') expect(meth).to have_tag(:return) expect(meth.tag(:return).types).to eq ['Boolean'] end it "does not change return type for method ending in ? with return types set" do meth = P('Foo#boolean3?') expect(meth).to have_tag(:return) expect(meth.tag(:return).types).to eq ['NotBoolean', 'nil'] end it "does not change return type for method ending in ? with return types set by @overload" do meth = P('Foo#rainy?') expect(meth).to have_tag(:overload) expect(meth.tag(:overload)).to have_tag(:return) expect(meth).not_to have_tag(:return) end it "adds method writer to existing attribute" do expect(Registry.at('Foo#attr_name')).to be_reader expect(Registry.at('Foo#attr_name=')).to be_writer end it "adds method reader to existing attribute" do expect(Registry.at('Foo#attr_name2')).to be_reader expect(Registry.at('Foo#attr_name2=')).to be_writer end it "generates an options parameter if @option refers to an undocumented parameter" do meth = P('Foo#auto_opts') expect(meth).to have_tag(:param) expect(meth.tag(:param).name).to eq "opts" expect(meth.tag(:param).types).to eq ["Hash"] end it "raises an undocumentable error when a method is defined on an object instance" do undoc_error "error = Foo; def error.at(foo) end" expect(Registry.at('error')).to be nil end it "allows class method to be defined on constant reference object" do expect(Registry.at('Foo.meth_on_const')).not_to be nil expect(Registry.at('Foo.meth2_on_const')).not_to be nil end it "copies alias information on method (re-)definition to new method" do expect(Registry.at('D').aliases).to be_empty expect(Registry.at('D#b').is_alias?).to be false expect(Registry.at('D#a').is_alias?).to be false end it "adds macros for class methods" do macro = CodeObjects::MacroObject.find('prop') expect(macro).not_to be nil expect(macro.macro_data).to eq "@!method $1(value)\n$3\n@return [$2]" expect(macro.method_object).to eq Registry.at('E.property') expect(macro).to be_attached obj = Registry.at('E#foo') expect(obj).not_to be nil expect(obj.docstring).to eq 'create a foo' expect(obj.signature).to eq 'def foo(value)' expect(obj.tag(:return).types).to eq ['String'] end it "handles macros on any object" do macro = CodeObjects::MacroObject.find('xyz') expect(macro).not_to be nil expect(macro.macro_data).to eq '@!method $1' end it "skips macros on instance methods" do expect(Registry.at('E#a')).to be nil end it "warns if the macro name is invalid" do expect(log).to receive(:warn).with(/Invalid directive.*@!macro/) YARD.parse_string "class Foo\n# @!macro\ndef self.foo; end\nend" end it "handles 'def end' methods" do obj = Registry.at('F::A#foo') expect(obj).not_to be nil obj = Registry.at('F::A#bar') expect(obj).not_to be nil expect(obj.docstring).to eq 'PASS' end end yard-0.9.12/spec/handlers/class_handler_spec.rb0000755000004100000410000002137513206751010021473 0ustar www-datawww-data# frozen_string_literal: true require File.expand_path(File.dirname(__FILE__) + '/spec_helper') RSpec.describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}ClassHandler" do before(:all) { parse_file :class_handler_001, __FILE__ } it "parses a class block with docstring" do expect(P("A").docstring).to eq "Docstring" end it "handles complex class names" do expect(P("A::B::C")).not_to eq nil end it "handles the subclassing syntax" do expect(P("A::B::C").superclass).to eq P(:String) expect(P("A::X").superclass).to eq Registry.at("A::B::C") end it "interprets class << self as a class level block" do expect(P("A.classmethod1")).not_to eq nil end it "interprets class << ClassName as a class level block in ClassName's namespace" do expect(P("A::B::C.Hello")).to be_instance_of(CodeObjects::MethodObject) end it "makes visibility public when parsing a block" do expect(P("A::B::C#method1").visibility).to eq :public end it "sets superclass type to :class if it is a Proxy" do expect(P("A::B::C").superclass.type).to eq :class end it "looks for a superclass before creating the class if it shares the same name" do expect(P('B::A').superclass).to eq P('A') end it "handles class definitions in the form ::ClassName" do expect(Registry.at("MyRootClass")).not_to be nil end it "handles superclass as a constant-style method (camping style < R /path/)" do expect(P('Test1').superclass).to eq P(:R) expect(P('Test2').superclass).to eq P(:R) expect(P('Test6').superclass).to eq P(:NotDelegateClass) end it "handles superclass with OStruct.new or Struct.new syntax (superclass should be OStruct/Struct)" do expect(P('Test3').superclass).to eq P(:Struct) expect(P('Test4').superclass).to eq P(:OStruct) end it "handles DelegateClass(CLASSNAME) superclass syntax" do expect(P('Test5').superclass).to eq P(:Array) end it "handles a superclass of the same name in the form ::ClassName" do expect(P('Q::Logger').superclass).to eq P(:Logger) expect(P('Q::Foo').superclass).not_to eq P('Q::Logger') end ["CallMethod('test')", "VSD^#}}", 'not.aclass', 'self'].each do |klass| it "raises 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 "raises an UndocumentableError for invalid superclass '#{klass}' but it should create the class." do expect(YARD::CodeObjects::ClassObject).to receive(:new).with(Registry.root, 'A') with_parser(:ruby18) { undoc_error "class A < #{klass}; end" } expect(Registry.at('A').superclass).to eq P(:Object) end end ['not.aclass', 'self', 'AnotherClass.new'].each do |klass| it "raises 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 expect(Registry.at(klass)).to be nil end end it "documents 'class << SomeConstant' by using SomeConstant's value as a reference to the real class name" do expect(Registry.at('String.classmethod')).not_to be nil end it "allows class << SomeRubyClass to create the class if it does not exist" do expect(Registry.at('Symbol.toString')).not_to be nil end it "documents 'class Exception' without running into superclass issues" do Parser::SourceParser.parse_string <<-eof class Exception end eof expect(Registry.at(:Exception)).not_to be nil end it "documents 'class RT < XX::RT' with proper superclass even if XX::RT is a proxy" do expect(Registry.at(:RT)).not_to be nil expect(Registry.at(:RT).superclass).to eq P('XX::RT') end it "does not overwrite docstring with an empty one" do expect(Registry.at(:Zebra).docstring).to eq "Docstring 2" end it "turns 'class Const < Struct.new(:sym)' into class Const with attr :sym" do obj = Registry.at("Point") expect(obj).to be_kind_of(CodeObjects::ClassObject) attrs = obj.attributes[:instance] [:x, :y, :z].each do |key| expect(attrs).to have_key(key) expect(attrs[key][:read]).not_to be nil expect(attrs[key][:write]).not_to be nil end end it "turns 'class Const < Struct.new('Name', :sym)' into class Const with attr :sym" do obj = Registry.at("AnotherPoint") expect(obj).to be_kind_of(CodeObjects::ClassObject) attrs = obj.attributes[:instance] [:a, :b, :c].each do |key| expect(attrs).to have_key(key) expect(attrs[key][:read]).not_to be nil expect(attrs[key][:write]).not_to be nil end expect(Registry.at("XPoint")).to be nil end it "creates a Struct::Name class when class Const < Struct.new('Name', :sym) is found" do obj = Registry.at("Struct::XPoint") expect(obj).not_to be nil end it "attaches 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| expect(attrs).to have_key(key) expect(attrs[key][:read]).not_to be nil expect(attrs[key][:write]).not_to be nil end end it "uses @attr to set attribute descriptions on Struct subclasses" do obj = Registry.at("DoccedStruct#input") expect(obj.docstring).to eq "the input stream" end it "uses @attr to set attribute types on Struct subclasses" do obj = Registry.at("DoccedStruct#someproc") expect(obj).not_to be nil expect(obj.tag(:return)).not_to be nil expect(obj.tag(:return).types).to eq ["Proc", "#call"] end it "defaults types unspecified by @attr to Object on Struct subclasses" do obj = Registry.at("DoccedStruct#mode") expect(obj).not_to be nil expect(obj.tag(:return)).not_to be nil expect(obj.tag(:return).types).to eq ["Object"] end it "creates parameters for writers of Struct subclass's attributes" do obj = Registry.at("DoccedStruct#input=") expect(obj.tags(:param).size).to eq 1 expect(obj.tag(:param).types).to eq ["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] expect(attrs[:first][:read]).not_to be nil expect(attrs[:first][:write]).not_to 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] expect(attrs[:second][:read]).not_to be nil expect(attrs[:second][:write]).to 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] expect(attrs[:third][:read]).to be nil expect(attrs[:third][:write]).not_to be nil end it "defines a reader with correct return types when @attr_reader is used on Structs" do obj = Registry.at("#{struct}#second") expect(obj.tag(:return).types).to eq ["Fixnum"] end it "defines a writer with correct parameter types when @attr_writer is used on Structs" do obj = Registry.at("#{struct}#third=") expect(obj.tag(:param).types).to eq ["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] expect(attrs[:fourth][:read]).not_to be nil expect(attrs[:fourth][:write]).not_to 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") expect(obj.tag(:return).types).to eq ["#read"] end it "uses @attr_writer for the setter when both @attr_reader and @attr_writer are given" do obj = Registry.at("#{struct}#fourth=") expect(obj.tag(:param).types).to eq ["IO"] end it "extracts text from @attr_reader" do expect(Registry.at("#{struct}#fourth").docstring).to eq "returns a proc that reads" end it "extracts text from @attr_writer" do expect(Registry.at("#{struct}#fourth=").docstring).to eq "sets the proc that writes stuff" end end end it "inherits from a regular struct" do expect(Registry.at('RegularStruct').superclass).to eq P(:Struct) expect(Registry.at('RegularStruct2').superclass).to eq P(:Struct) end it "handles inheritance from 'self'" do expect(Registry.at('Outer1::Inner1').superclass).to eq Registry.at('Outer1') end end yard-0.9.12/spec/handlers/attribute_handler_spec.rb0000755000004100000410000000562213206751010022366 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.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 = namespace.to_s + "#" + name.to_s wname = namespace.to_s + "#" + name.to_s + "=" if read expect(Registry.at(rname)).to be_instance_of(CodeObjects::MethodObject) else expect(Registry.at(rname)).to eq nil end if write expect(Registry.at(wname)).to be_kind_of(CodeObjects::MethodObject) else expect(Registry.at(wname)).to eq nil end attrs = Registry.at(namespace).attributes[scope][name] expect(attrs[:read]).to eq(read ? Registry.at(rname) : nil) expect(attrs[:write]).to eq(write ? Registry.at(wname) : nil) end it "parses attributes inside modules too" do expect(Registry.at("A#x=")).not_to eq nil end it "parses 'attr'" do read_write(:B, :a, true, true) read_write(:B, :a2, true, false) read_write(:B, "a3", true, false) end it "parses 'attr_reader'" do read_write(:B, :b, true, false) end it "parses 'attr_writer'" do read_write(:B, :e, false, true) end it "parses 'attr_accessor'" do read_write(:B, :f, true, true) end it "parses 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 "has a default docstring if one is not supplied" do expect(Registry.at("B#f=").docstring).not_to be_empty end it "sets the correct docstring if one is supplied" do expect(Registry.at("B#b").docstring).to eq "Docstring" expect(Registry.at("B#c").docstring).to eq "Docstring" expect(Registry.at("B#d").docstring).to eq "Docstring" end it "is able to differentiate between class and instance attributes" do expect(P('B').class_attributes[:z][:read].scope).to eq :class expect(P('B').instance_attributes[:z][:read].scope).to eq :instance end it "responds true in method's #is_attribute?" do expect(P('B#a').is_attribute?).to be true expect(P('B#a=').is_attribute?).to be true end it "does not return true for #is_explicit? in created methods" do Registry.at(:B).meths.each do |meth| expect(meth.is_explicit?).to be false end end it "handles attr call with no arguments" do expect { StubbedSourceParser.parse_string "attr" }.not_to raise_error end it "adds existing reader method as part of attr_writer combo" do expect(Registry.at('C#foo=').attr_info[:read]).to eq Registry.at('C#foo') end it "adds existing writer method as part of attr_reader combo" do expect(Registry.at('C#foo').attr_info[:write]).to eq Registry.at('C#foo=') end it "maintains visibility for attr_reader" do expect(Registry.at('D#parser').visibility).to eq :protected end end yard-0.9.12/spec/handlers/ruby/0000755000004100000410000000000013206751010016300 5ustar www-datawww-datayard-0.9.12/spec/handlers/ruby/legacy/0000755000004100000410000000000013206751010017544 5ustar www-datawww-datayard-0.9.12/spec/handlers/ruby/legacy/base_spec.rb0000755000004100000410000000521213206751010022020 0ustar www-datawww-data# frozen_string_literal: true include Parser::Ruby::Legacy RSpec.describe YARD::Handlers::Ruby::Legacy::Base, "#handles and inheritance" do before do allow(Handlers::Ruby::Legacy::Base).to receive(:inherited) if RUBY_VERSION > '1.8.7' allow(Handlers::Ruby::Legacy::MixinHandler).to receive(:inherited) # fixes a Ruby1.9 issue end @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 "only handles Handlers inherited from Ruby::Legacy::Base class" do class IgnoredHandler < Handlers::Base handles "hello" end class NotIgnoredHandlerLegacy < Handlers::Ruby::Legacy::Base handles "hello" end allow(Handlers::Base).to receive(:subclasses).and_return [IgnoredHandler, NotIgnoredHandlerLegacy] expect(@processor.find_handlers(stmt("hello world"))).to eq [NotIgnoredHandlerLegacy] end it "handles a string input" do class TestStringHandler < Handlers::Ruby::Legacy::Base handles "hello" end expect(TestStringHandler.handles?(stmt("hello world"))).to be true expect(TestStringHandler.handles?(stmt("nothello world"))).to be false end it "handles regex input" do class TestRegexHandler < Handlers::Ruby::Legacy::Base handles(/^nothello$/) end expect(TestRegexHandler.handles?(stmt("nothello"))).to be true expect(TestRegexHandler.handles?(stmt("not hello hello"))).to be false end it "handles token input" do class TestTokenHandler < Handlers::Ruby::Legacy::Base handles TkMODULE end expect(TestTokenHandler.handles?(stmt("module"))).to be true expect(TestTokenHandler.handles?(stmt("if"))).to be false end it "parses 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 allow(Handlers::Base).to receive(:subclasses).and_return [MyBlockHandler, MyBlockInnerHandler] Parser::SourceParser.parser_type = :ruby18 Parser::SourceParser.parse_string "myMethod do inner end" expect(MyBlockInnerHandler).to be_reached MyBlockInnerHandler.reset Parser::SourceParser.parse_string "myMethod { inner }" expect(MyBlockInnerHandler).to be_reached Parser::SourceParser.parser_type = :ruby end end yard-0.9.12/spec/handlers/ruby/base_spec.rb0000755000004100000410000000607013206751010020557 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::Handlers::Ruby::Base, '#valid_handler?' do include YARD::Parser::Ruby YARD::Parser::Ruby::AstNode # rubocop:disable Lint/Void before do allow(Handlers::Ruby::Base).to receive(:inherited) @processor = Handlers::Processor.new(OpenStruct.new(:parser_type => :ruby)) end after(:all) do Handlers::Base.clear_subclasses end def valid(handler, stmt) expect(@processor.find_handlers(stmt)).to include(handler) end def invalid(handler, stmt) expect(@processor.find_handlers(stmt)).not_to include(handler) end it "only handles Handlers inherited from Ruby::Base class" do class IgnoredHandler < Handlers::Base handles :list end class NotIgnoredHandler < Handlers::Ruby::Base handles :list end allow(Handlers::Base).to receive(:subclasses).and_return [IgnoredHandler, NotIgnoredHandler] expect(@processor.find_handlers(s)).to eq [NotIgnoredHandler] end it "handles string input (matches AstNode#source)" do class StringHandler < Handlers::Ruby::Base handles "x" end allow(Handlers::Base).to receive(: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 "handles symbol input (matches AstNode#type)" do class SymbolHandler < Handlers::Ruby::Base handles :myNodeType end allow(Handlers::Base).to receive(:subclasses).and_return [SymbolHandler] valid SymbolHandler, s(:myNodeType, s(1, 2, 3)) invalid SymbolHandler, s(:NOTmyNodeType, s(1, 2, 3)) end it "handles regex input (matches AstNode#source)" do class RegexHandler < Handlers::Ruby::Base handles(/^if x ==/) end allow(Handlers::Base).to receive(: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 "handles AstNode input (matches AST literally)" do class ASTHandler < Handlers::Ruby::Base handles s(:vcall, s(:ident, "hello_world")) end allow(Handlers::Base).to receive(:subclasses).and_return [ASTHandler] valid ASTHandler, s(:vcall, s(:ident, "hello_world")) invalid ASTHandler, s(:vcall, s(:ident, "NOTHELLOWORLD")) end it "handles #method_call(:methname) on a valid AST" do class MethCallHandler < Handlers::Ruby::Base handles method_call(:meth) end allow(Handlers::Base).to receive(: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.9.12/spec/handlers/class_method_handler_shared_examples.rb0000755000004100000410000000676413206751010025252 0ustar www-datawww-data# frozen_string_literal: true RSpec.shared_examples "class method visibility decorator" do # Use let(:visibility) to specify the name of the x_class_method # visibility decorator to test. describe do before do StubbedSourceParser.parse_string <<-CODE class A def self.b; end def self.c; end def self.d; end def self.e; end #{visibility}_class_method(:c, :d) #{visibility}_class_method("e") end CODE end it "handles private_class_method statement" do expect(Registry.at('A.c').visibility).to eq visibility expect(Registry.at('A.d').visibility).to eq visibility expect(Registry.at('A.e').visibility).to eq visibility end # Issue #760 # https://github.com/lsegal/yard/issues/760 it "handles singleton classes" do # Note: It's important to def a method within the singleton class or # the bug may not trigger. code = <<-CODE class SingletonClass private_class_method :new def self.foo "foo" end end CODE StubbedSourceParser.parse_string(code) # Should be successful. end unless LEGACY_PARSER end describe "handles reopened class" do before do StubbedSourceParser.parse_string <<-CODE class SingletonClass #{'private' unless visibility.to_sym == :private} # != visibility def self.foo 'foo' end # == visibility def self.bar end # == visibility from reopening class. def self.baz end #{visibility}_class_method :new, :bar end CODE StubbedSourceParser.parse_string <<-CODE # Reopening singleton class. class SingletonClass #{visibility}_class_method :baz #{'private' unless visibility.to_sym == :private} # != visibility from reopened class. (Verifies class was reopened.) def self.bat end end CODE end specify do expect(Registry.at('SingletonClass.foo').visibility).not_to eq visibility expect(Registry.at('SingletonClass.bar').visibility).to eq visibility expect(Registry.at('SingletonClass.baz').visibility).to eq visibility expect(Registry.at('SingletonClass.bat').visibility).not_to eq visibility end end unless LEGACY_PARSER # reopened class describe "as method definition decorator" do subject { Registry.at('SingletonClass.foo') } # Valid as of Ruby 2.1.0: # private_class_method def self.foo; end let(:code) do <<-CODE class SingletonClass # Valid Ruby 2.1.0 syntax. #{method_def} 'it works' end end CODE end let(:method_def) { "#{visibility}_class_method def self.foo param1, param2" } before { StubbedSourceParser.parse_string code } it "handles self.foo" do expect(subject.visibility).to eq visibility end it "handles parameters correctly" do expect(subject.parameters.map(&:first)).to eq ['param1', 'param2'] end it "attaches documentation to method definition" do expect(subject.docstring).to eq "Valid Ruby 2.1.0 syntax." end describe "handles SingletonClass.foo" do let(:method_def) { "#{visibility}_class_method def SingletonClass.foo" } specify do expect(subject.visibility).to eq visibility end end end unless LEGACY_PARSER end yard-0.9.12/spec/handlers/public_class_method_handler_spec.rb0000755000004100000410000000056513206751010024367 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' require File.dirname(__FILE__) + '/class_method_handler_shared_examples' RSpec.describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}PublicClassMethodHandler" do before { Registry.clear } let(:visibility) { :public } include_examples "class method visibility decorator" end yard-0.9.12/spec/handlers/yield_handler_spec.rb0000755000004100000410000000426613206751010021474 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}YieldHandler" do before(:all) { parse_file :yield_handler_001, __FILE__ } it "only parses yield blocks in methods" do expect(P(:Testing).tag(:yield)).to be nil expect(P(:Testing).tag(:yieldparam)).to be nil end it "handles an empty yield statement" do expect(P('Testing#mymethod').tag(:yield)).to be nil expect(P('Testing#mymethod').tag(:yieldparam)).to be nil end it "does not document a yield statement in a method with either @yield or @yieldparam" do expect(P('Testing#mymethod2').tag(:yield).types).to eq ['a', 'b'] expect(P('Testing#mymethod2').tag(:yield).text).to eq "Blah" expect(P('Testing#mymethod2').tags(:yieldparam).size).to eq 2 expect(P('Testing#mymethod3').tag(:yield).types).to eq ['a', 'b'] expect(P('Testing#mymethod3').tags(:yieldparam).size).to eq 0 expect(P('Testing#mymethod4').tag(:yieldparam).name).to eq '_self' expect(P('Testing#mymethod4').tag(:yieldparam).text).to eq 'BLAH' end it "handles any arbitrary yield statement" do expect(P('Testing#mymethod5').tag(:yield).types).to eq [':a', 'b', '_self', 'File.read(\'file\', \'w\')', 'CONSTANT'] end it "handles parentheses" do expect(P('Testing#mymethod6').tag(:yield).types).to eq ['b', 'a'] end it "only documents the first yield statement in a method (limitation of yield handler)" do expect(P('Testing#mymethod7').tag(:yield).types).to eq ['a'] end it "handles `self` keyword and list object type as yieldparam for _self" do expect(P('Testing#mymethod8').tag(:yield).types).to eq ['_self'] expect(P('Testing#mymethod8').tag(:yieldparam).types).to eq ['Testing'] expect(P('Testing#mymethod8').tag(:yieldparam).text).to eq "the object that the method was called on" end it "handles `super` keyword and document it under _super" do expect(P('Testing#mymethod9').tag(:yield).types).to eq ['_super'] expect(P('Testing#mymethod9').tag(:yieldparam).types).to be nil expect(P('Testing#mymethod9').tag(:yieldparam).text).to eq "the result of the method from the superclass" end end yard-0.9.12/spec/templates/0000755000004100000410000000000013206751010015515 5ustar www-datawww-datayard-0.9.12/spec/templates/examples/0000755000004100000410000000000013206751010017333 5ustar www-datawww-datayard-0.9.12/spec/templates/examples/module004.html0000755000004100000410000001246513206751010021745 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.9.12/spec/templates/examples/module001.txt0000755000004100000410000000067313206751010021613 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.9.12/spec/templates/examples/method005.txt0000755000004100000410000000140513206751010021604 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.9.12/spec/templates/examples/method001.html0000755000004100000410000000467513206751010021741 0ustar www-datawww-data

            Method: #m

            Defined in:
            (stdin)

            #m(x) ⇒ String (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.9.12/spec/templates/examples/constant002.txt0000755000004100000410000000035513206751010022155 0ustar www-datawww-data------------------------------------------------------ Constant: MYCONST MYCONST = 'foo' ------------------------------------------------------------------------ ------------------------------------------------------------------------yard-0.9.12/spec/templates/examples/module002.html0000755000004100000410000001073613206751010021742 0ustar www-datawww-data

            Module: A

            Defined in:
            (stdin)

            Foo collapse

            • #foo_attr
              Returns the value of attribute foo_attr.

            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.9.12/spec/templates/examples/module001.dot0000755000004100000410000000127313206751010021557 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.9.12/spec/templates/examples/class001.html0000755000004100000410000001116213206751010021553 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

            #initialize(test) ⇒ A

            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.9.12/spec/templates/examples/module003.html0000755000004100000410000000504413206751010021737 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.9.12/spec/templates/examples/module001.html0000755000004100000410000002766013206751010021745 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

            • #attr1
              Returns the value of attribute attr1.
            • #attr2 readonly
              Returns the value of attribute attr2.
            • #attr3
            • #attr4 writeonly
              Sets the attribute attr4.

            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

            #attr3String #attr3=(value)

            Overloads:

            • #attr3String
              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.9.12/spec/templates/examples/method005.html0000755000004100000410000000331513206751010021733 0ustar www-datawww-data

            Method: #m

            Defined in:
            (stdin)

            #m(a) ⇒ void #m(b)

            Overloads:

            • #m(a) ⇒ void

              This method returns an undefined value.

            • #m(b)

              Parameters:

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

            Method: #m

            Defined in:
            (stdin)

            #m(*args) ⇒ void

            This method returns an undefined value.

            
            
            2
            # File '(stdin)', line 2
            
            def m(*args) end
            yard-0.9.12/spec/templates/examples/method002.html0000755000004100000410000000251513206751010021731 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.9.12/spec/templates/examples/method006.html0000755000004100000410000000325513206751010021737 0ustar www-datawww-data

            Method: #m

            Defined in:
            (stdin)

            #m(x, y, *args, kword1: 123, kword2:)

            Parameters:

            • x (String)
              the x argument
            • y (Boolean)
              the y argument
            • keyword (kword1)
              1
            • keyword (kword2)
              2
            
            
            5
            # File '(stdin)', line 5
            
            def m(x, y, *args, kword1: 123, kword2:, **) end
            yard-0.9.12/spec/templates/examples/method006.txt0000755000004100000410000000064313206751010021610 0ustar www-datawww-data------------------------------------------------------------- Method: #m (Defined in: (stdin)) root.m(x, y, *args, kword1: 123, kword2:) ------------------------------------------------------------------------ Parameters: ----------- (String) x - the x argument (Boolean) y - the y argument (kword1) keyword - 1 (kword2) keyword - 2 yard-0.9.12/spec/templates/examples/method003.txt0000755000004100000410000000175513206751010021612 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.9.12/spec/templates/examples/tag001.txt0000755000004100000410000000203513206751010021073 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.9.12/spec/templates/examples/class002.html0000755000004100000410000000070613206751010021556 0ustar www-datawww-data

            Class: D

            Inherits:
            Object
            • Object
            show all
            Defined in:
            (stdin)
            yard-0.9.12/spec/templates/examples/method004.txt0000755000004100000410000000045313206751010021605 0ustar www-datawww-data------------------------------------------------------------- Method: #m (Defined in: (stdin)) root.m(*args) -> void ------------------------------------------------------------------------ This method returns an undefined value. yard-0.9.12/spec/templates/examples/method003.html0000755000004100000410000000523113206751010021730 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.9.12/spec/templates/examples/class001.txt0000755000004100000410000000070213206751010021424 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.9.12/spec/templates/examples/method002.txt0000755000004100000410000000054613206751010021606 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.9.12/spec/templates/examples/method001.txt0000755000004100000410000000120313206751010021574 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.9.12/spec/templates/examples/constant001.txt0000755000004100000410000000112013206751010022143 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.9.12/spec/templates/examples/constant003.txt0000755000004100000410000000050413206751010022152 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.9.12/spec/templates/onefile_spec.rb0000755000004100000410000000333613206751010020505 0ustar www-datawww-data# frozen_string_literal: true require 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 RSpec.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 = String.new("") 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 "renders html" do render expect(@files).to eq ['index.html'] expect(@output).to include("This is a code comment") expect(@output).to include("This is a license!") expect(@output).to include("Class: A") expect(@output).to include("Foo method") expect(@output).to include("Bar method") end end yard-0.9.12/spec/templates/constant_spec.rb0000755000004100000410000000267413206751010020721 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + "/spec_helper" RSpec.describe YARD::Templates::Engine.template(:default, :constant) do describe "fully dressed constant" do it "renders 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 "renders 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 end yard-0.9.12/spec/templates/module_spec.rb0000755000004100000410000000767213206751010020360 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.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 "renders 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 "renders 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 "renders dot format correctly" do expect(Registry.at('A').format(:format => :dot, :dependencies => true, :full => true)).to eq example_contents(:module001, 'dot') end it "renders 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 "ignores 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 "embeds 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.9.12/spec/templates/class_spec.rb0000755000004100000410000000202013206751010020156 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.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 "renders html format correctly" do html_equals(Registry.at('A').format(html_options), :class001) end it "renders text format correctly" do text_equals(Registry.at('A').format, :class001) end it "hides private constructors" do html_equals(Registry.at('D').format(html_options(:verifier => Verifier.new("!@private"))), :class002) end end yard-0.9.12/spec/templates/spec_helper.rb0000755000004100000410000000346413206751010020345 0ustar www-datawww-data# frozen_string_literal: true include YARD::Templates def only_copy?(result, example, type) return false unless defined?($COPY) 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) expect(result).to eq 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) result = String.new(result) expected = String.new(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.9.12/spec/templates/section_spec.rb0000755000004100000410000001043313206751010020524 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe YARD::Templates::Section do include YARD::Templates describe "#initialize" do it "converts first argument to splat if it is array" do s = Section.new(:name, [:foo, :bar]) expect(s.name).to eq :name expect(s[0].name).to eq :foo expect(s[1].name).to eq :bar end it "allows initialization with Section objects" do s = Section.new(:name, [:foo, Section.new(:bar)]) expect(s.name).to eq :name expect(s[0]).to eq Section.new(:foo) expect(s[1]).to eq Section.new(:bar) end it "makes a list of sections" do s = Section.new(:name, [:foo, [:bar]]) expect(s).to eq Section.new(:name, Section.new(:foo, Section.new(:bar))) end end describe "#[]" do it "uses Array#[] if argument is integer" do expect(Section.new(:name, [:foo, :bar])[0].name).to eq :foo end it "returns new Section object if more than one argument" do expect(Section.new(:name, :foo, :bar, :baz)[1, 2]).to eq Section.new(:name, :bar, :baz) end it "returns new Section object if arg is Range" do expect(Section.new(:name, :foo, :bar, :baz)[1..2]).to eq Section.new(:name, :bar, :baz) end it "looks for section by name if arg is object" do expect(Section.new(:name, :foo, :bar, [:baz])[:bar][:baz]).to eq Section.new(:baz) end end describe "#eql?" do it "checks for equality of two equal sections" do expect(Section.new(:foo, [:a, :b])).to eql(Section.new(:foo, :a, :b)) expect(Section.new(:foo, [:a, :b])).to eq Section.new(:foo, :a, :b) end it "is not equal if section names are different" do expect(Section.new(:foo, [:a, :b])).not_to eql(Section.new(:bar, :a, :b)) expect(Section.new(:foo, [:a, :b])).not_to eq Section.new(:bar, :a, :b) end end describe "#==" do it "allows comparison to Symbol" do expect(Section.new(:foo, 2, 3)).to eq :foo end it "allows comparison to String" do expect(Section.new("foo", 2, 3)).to eq "foo" end it "allows comparison to Template" do t = YARD::Templates::Engine.template!(:xyzzy, '/full/path/xyzzy') expect(Section.new(t, 2, 3)).to eq t end it "allows comparison to Section" do expect(Section.new(1, [2, 3])).to eq Section.new(1, 2, 3) end it "allows comparison to Object" do expect(Section.new(1, [2, 3])).to eq 1 end it "allows comparison to Array" do expect(Section.new(1, 2, [3])).to eq [1, [2, [3]]] end end describe "#to_a" do it "converts Section to regular Array list" do arr = Section.new(1, 2, [3, [4]]).to_a expect(arr.class).to eq Array expect(arr).to eq [1, [2, [3, [4]]]] end end describe "#place" do it "places objects as Sections" do expect(Section.new(1, 2, 3).place(4).before(3)).to eq [1, [2, 4, 3]] end it "places objects anywhere inside Section with before/after_any" do expect(Section.new(1, 2, [3, [4]]).place(5).after_any(4)).to eq [1, [2, [3, [4, 5]]]] expect(Section.new(1, 2, [3, [4]]).place(5).before_any(4)).to eq [1, [2, [3, [5, 4]]]] end it "allows multiple sections to be placed" do expect(Section.new(1, 2, 3).place(4, 5).after(3).to_a).to eq [1, [2, 3, 4, 5]] expect(Section.new(1, 2, 3).place(4, [5]).after(3).to_a).to eq [1, [2, 3, 4, [5]]] end end describe "#push" do it "pushes objects as Sections" do s = Section.new(:foo) s.push :bar expect(s[0]).to eq Section.new(:bar) end it "is aliased as #<<" do s = Section.new(1) s << :index expect(s[:index]).to be_a(Section) end end describe "#unshift" do it "unshifts objects as Sections" do s = Section.new(:foo) s.unshift :bar expect(s[0]).to eq Section.new(:bar) end end describe "#any" do it "finds item inside sections" do s = Section.new(:foo, Section.new(:bar, Section.new(:bar))) s.any(:bar).push(:baz) expect(s.to_a).to eq [:foo, [:bar, [:bar, :baz]]] end it "finds item in any deeply nested set of sections" do s = Section.new(:foo, Section.new(:bar, Section.new(:baz))) s.any(:baz).push(:qux) expect(s.to_a).to eq [:foo, [:bar, [:baz, [:qux]]]] end end end yard-0.9.12/spec/templates/method_spec.rb0000755000004100000410000000550413206751010020343 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' # $COPY = :method001 # $COPYT = :html RSpec.describe YARD::Templates::Engine.template(:default, :method) do before { Registry.clear } shared_examples_for "all formats" do it "renders html format correctly" do html_equals(Registry.at('#m').format(html_options), @template) end it "renders 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 describe "method with keyword arguments spalt" do before do @template = :method006 YARD.parse_string <<-'eof' # @param [String] x the x argument # @param [Boolean] y the y argument # @param [kword1] keyword 1 # @param [kword2] keyword 2 def m(x, y, *args, kword1: 123, kword2:, **) end eof end it_should_behave_like "all formats" end end yard-0.9.12/spec/templates/helpers/0000755000004100000410000000000013206751010017157 5ustar www-datawww-datayard-0.9.12/spec/templates/helpers/markup/0000755000004100000410000000000013206751010020456 5ustar www-datawww-datayard-0.9.12/spec/templates/helpers/markup/rdoc_markup_spec.rb0000755000004100000410000000560113206751010024330 0ustar www-datawww-data# frozen_string_literal: true RSpec.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 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 it "loads RDoc2.x if rdoc/markup is present" do @good_libs += ['rdoc/markup', 'rdoc/markup/to_html'] expect(load_markup).to eq :RDoc2 end it "fails on RDoc2.x if rdoc/markup/to_html is not present" do @good_libs += ['rdoc/markup'] expect { load_markup }.to raise_error(NameError) end it "loads 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'] expect(load_markup).to eq :RDoc1 end it "raises an error on loading if neither lib is present" do expect { load_markup }.to 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 expect(to_html('Hello ++')).to eq '

            Hello <code>

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

            +foo+

            ")).to eq "

            foo

            " end end end yard-0.9.12/spec/templates/helpers/module_helper_spec.rb0000755000004100000410000000176313206751010023354 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::Templates::Helpers::ModuleHelper do include YARD::Templates::Helpers::BaseHelper include YARD::Templates::Helpers::ModuleHelper describe "#prune_method_listing" do before { YARD::Registry.clear } let(:options) { OpenStruct.new } let(:object) { YARD::Registry.at("Foo#bar") } let(:objects) { [object] } it "filters aliases" do YARD.parse_string "class Foo; def orig; end; alias bar orig end" expect(prune_method_listing(objects)).to eq [] end it "filters attributes" do YARD.parse_string "class Foo; attr_accessor :bar end" expect(prune_method_listing(objects)).to eq [] end it "ignores methods if namespace object is filtered" do YARD.parse_string <<-eof # @author test class Foo def bar; end end eof options.verifier = YARD::Verifier.new('@author.text != "test"') expect(prune_method_listing(objects)).to eq [] end end end yard-0.9.12/spec/templates/helpers/shared_signature_examples.rb0000755000004100000410000000723113206751010024737 0ustar www-datawww-data# frozen_string_literal: true RSpec.shared_examples_for "signature" do before do YARD::Registry.clear @options = Templates::TemplateOptions.new @options.reset_defaults allow(self).to receive(:options).and_return(@options) end def trim(sig) sig.gsub(/\s+/, ' ') end it "shows signature for regular instance method" do YARD.parse_string "def foo; end" expect(trim(signature(Registry.at('#foo')))).to eq @results[:regular] end it "allows default return type to be changed" do @options.default_return = "Hello" YARD.parse_string "def foo; end" expect(trim(signature(Registry.at('#foo')))).to eq @results[:default_return] end it "allows default return type to be omitted" do @options.default_return = "" YARD.parse_string "def foo; end" expect(trim(signature(Registry.at('#foo')))).to eq @results[:no_default_return] end it "shows signature for private class method" do YARD.parse_string "class A; private; def self.foo; end end" expect(trim(signature(Registry.at('A.foo')))).to eq @results[:private_class] end it "shows return type for single type" do YARD.parse_string <<-'eof' # @return [String] def foo; end eof expect(trim(signature(Registry.at('#foo')))).to eq @results[:single] end it "shows return type for 2 types" do YARD.parse_string <<-'eof' # @return [String, Symbol] def foo; end eof expect(trim(signature(Registry.at('#foo')))).to eq @results[:two_types] end it "shows return type for 2 types over multiple tags" do YARD.parse_string <<-'eof' # @return [String] # @return [Symbol] def foo; end eof expect(trim(signature(Registry.at('#foo')))).to eq @results[:two_types_multitag] end it "shows 'Type?' if return types are [Type, nil]" do YARD.parse_string <<-'eof' # @return [Type, nil] def foo; end eof expect(trim(signature(Registry.at('#foo')))).to eq @results[:type_nil] end it "shows 'Type?' if return types are [Type, nil, nil] (extra nil)" do YARD.parse_string <<-'eof' # @return [Type, nil] # @return [nil] def foo; end eof expect(trim(signature(Registry.at('#foo')))).to eq @results[:type_nil] end it "shows 'Type+' if return types are [Type, Array]" do YARD.parse_string <<-'eof' # @return [Type, ] def foo; end eof expect(trim(signature(Registry.at('#foo')))).to eq @results[:type_array] end it "shows (Type, ...) for more than 2 return types" do YARD.parse_string <<-'eof' # @return [Type, ] # @return [AnotherType] def foo; end eof expect(trim(signature(Registry.at('#foo')))).to eq @results[:multitype] end it "shows (void) for @return [void] by default" do YARD.parse_string <<-'eof' # @return [void] def foo; end eof expect(trim(signature(Registry.at('#foo')))).to eq @results[:void] end it "does 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 expect(trim(signature(Registry.at('#foo')))).to eq @results[:hide_void] end it "shows block for method with yield" do YARD.parse_string <<-'eof' def foo; yield(a, b, c) end eof expect(trim(signature(Registry.at('#foo')))).to eq @results[:block] end it "uses regular return tag if the @overload is empty" do YARD.parse_string <<-'eof' # @overload foobar # Hello world # @return [String] def foo; end eof expect(trim(signature(Registry.at('#foo').tag(:overload)))).to eq @results[:empty_overload] end end yard-0.9.12/spec/templates/helpers/markup_helper_spec.rb0000755000004100000410000001246113206751010023363 0ustar www-datawww-data# frozen_string_literal: true 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 RSpec.describe YARD::Templates::Helpers::MarkupHelper do before do YARD::Templates::Helpers::MarkupHelper.clear_markup_cache end describe "#load_markup_provider" do before do allow(log).to receive(:error) @gen = GeneratorMock.new @gen.options.reset_defaults end it "exits on an invalid markup type" do @gen.options.markup = :invalid expect(@gen.load_markup_provider).to be false end it "fails when an invalid markup provider is specified" do @gen.options.update(:markup => :markdown, :markup_provider => :invalid) expect(@gen.load_markup_provider).to be false expect(@gen.markup_class).to eq nil end it "loads RDocMarkup if rdoc is specified and it is installed" do @gen.options.markup = :rdoc expect(@gen.load_markup_provider).to be true expect(@gen.markup_class).to eq YARD::Templates::Helpers::Markup::RDocMarkup end it "fails if RDoc cannot be loaded" do @gen.options.markup = :rdoc expect(@gen).to receive(:eval).with('::YARD::Templates::Helpers::Markup::RDocMarkup').and_raise(NameError) expect(@gen.load_markup_provider).to be false expect(@gen.markup_provider).to eq nil end it "searches through available markup providers for the markup type if none is set" do expect(@gen).to receive(:eval).with('::RedcarpetCompat').and_return(double(:bluecloth)) expect(@gen).to receive(:require).with('redcarpet').and_return(true) expect(@gen).not_to 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 expect(@gen.load_markup_provider).to be true expect(@gen.markup_provider).to eq :redcarpet end it "continues searching if some of the providers are unavailable" do expect(@gen).to receive(:require).with('redcarpet').and_raise(LoadError) expect(@gen).to receive(:require).with('rdiscount').and_raise(LoadError) expect(@gen).to receive(:require).with('kramdown').and_raise(LoadError) expect(@gen).to receive(:require).with('bluecloth').and_raise(LoadError) expect(@gen).to receive(:require).with('maruku').and_raise(LoadError) expect(@gen).to receive(:require).with('rpeg-markdown').and_return(true) expect(@gen).to 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 expect(@gen.markup_provider).to eq :"rpeg-markdown" end it "overrides the search if `:markup_provider` is set in options" do expect(@gen).to receive(:require).with('rdiscount').and_return(true) expect(@gen).to receive(:eval).with('::RDiscount').and_return(true) @gen.options.update(:markup => :markdown, :markup_provider => :rdiscount) @gen.load_markup_provider expect(@gen.markup_provider).to eq :rdiscount end it "fails if no provider is found" do YARD::Templates::Helpers::MarkupHelper::MARKUP_PROVIDERS[:markdown].each do |p| expect(@gen).to receive(:require).with(p[:lib].to_s).and_raise(LoadError) end @gen.options.markup = :markdown expect(@gen.load_markup_provider).to be false expect(@gen.markup_provider).to eq nil end it "fails if overridden provider is not found" do expect(@gen).to receive(:require).with('rdiscount').and_raise(LoadError) @gen.options.update(:markup => :markdown, :markup_provider => :rdiscount) expect(@gen.load_markup_provider).to be false expect(@gen.markup_provider).to eq nil end it "fails if the markup type is not found" do expect(log).to receive(:error).with(/Invalid markup/) @gen.options.markup = :xxx expect(@gen.load_markup_provider).to be false expect(@gen.markup_provider).to eq nil end end describe "#markup_for_file" do include YARD::Templates::Helpers::MarkupHelper it "looks for a shebang line" do expect(markup_for_file("#!text\ntext here", 'file.rdoc')).to eq :text end it "returns the default markup type if no shebang is found or no valid ext is found" do allow(self).to receive(:options).and_return(Options.new.update(:markup => :default_type)) expect(markup_for_file('', 'filename')).to eq :default_type end it "looks for a file extension if no shebang is found" do expect(markup_for_file('', 'filename.MD')).to eq :markdown expect(markup_for_file('', 'filename.ORG')).to eq :org end Templates::Helpers::MarkupHelper::MARKUP_EXTENSIONS.each do |type, exts| exts.each do |ext| it "recognizes .#{ext} as #{type} markup type" do expect(markup_for_file('', "filename.#{ext}")).to eq type end end end end end yard-0.9.12/spec/templates/helpers/method_helper_spec.rb0000755000004100000410000000455713206751010023353 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::Templates::Helpers::MethodHelper do include YARD::Templates::Helpers::BaseHelper include YARD::Templates::Helpers::MethodHelper describe "#format_args" do it "displays keyword arguments" do params = [['a:', '1'], ['b:', '2'], ['**kwargs', nil]] YARD.parse_string 'def foo; end' allow(Registry.at('#foo')).to receive(:parameters) { params } expect(format_args(Registry.at('#foo'))).to eq '(a: 1, b: 2, **kwargs)' end it "does not show &blockarg if no @param tag and has @yield" do YARD.parse_string <<-'eof' # @yield blah def foo(&block); end eof expect(format_args(Registry.at('#foo'))).to eq '' end it "does not show &blockarg if no @param tag and has @yieldparam" do YARD.parse_string <<-'eof' # @yieldparam blah test def foo(&block); end eof expect(format_args(Registry.at('#foo'))).to eq '' end it "shows &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 expect(format_args(Registry.at('#foo'))).to eq '(&block)' end end describe "#format_block" do before { YARD::Registry.clear } it "shows block for method with yield" do YARD.parse_string <<-'eof' def foo; yield(a, b, c) end eof expect(format_block(Registry.at('#foo'))).to eq "{|a, b, c| ... }" end it "shows block for method with @yieldparam tags" do YARD.parse_string <<-'eof' # @yieldparam _self me! def foo; end eof expect(format_block(Registry.at('#foo'))).to eq "{|_self| ... }" end it "shows 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 expect(format_block(Registry.at('#foo'))).to eq "{|a| ... }" expect(format_block(Registry.at('#foo2'))).to eq "{ ... }" end it "shows block for method with @yield and types" do YARD.parse_string <<-'eof' # @yield [a, b, c] blah # @yieldparam a def foo; end eof expect(format_block(Registry.at('#foo'))).to eq "{|a, b, c| ... }" end end end yard-0.9.12/spec/templates/helpers/html_helper_spec.rb0000755000004100000410000006256013206751010023035 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + "/shared_signature_examples" require 'ostruct' RSpec.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 "uses #h to escape HTML" do expect(h('Usage: foo "bar" ')).to eq "Usage: foo "bar" <baz>" end end describe "#charset" do it "returns foo if LANG=foo" do expect(ENV).to receive(:[]).with('LANG').and_return('shift_jis') if YARD.ruby18? expect(Encoding.default_external).to receive(:name).and_return('shift_jis') if defined?(Encoding) expect(charset).to eq 'shift_jis' end ['US-ASCII', 'ASCII-7BIT', 'ASCII-8BIT'].each do |type| it "converts #{type} to iso-8859-1" do expect(ENV).to receive(:[]).with('LANG').and_return(type) if YARD.ruby18? expect(Encoding.default_external).to receive(:name).and_return(type) if defined?(Encoding) expect(charset).to eq 'iso-8859-1' end end it "supports utf8 as an encoding value for utf-8" do type = 'utf8' expect(ENV).to receive(:[]).with('LANG').and_return(type) if YARD.ruby18? expect(Encoding.default_external).to receive(:name).and_return(type) if defined?(Encoding) expect(charset).to eq 'utf-8' end it "takes file encoding if there is a file" do @file = OpenStruct.new(:contents => String.new('foo').force_encoding('sjis')) # not the correct charset name, but good enough expect(['Shift_JIS', 'Windows-31J']).to include(charset) end if YARD.ruby19? it "takes file encoding if there is a file" do allow(ENV).to receive(:[]).with('LANG').and_return('utf-8') if YARD.ruby18? @file = OpenStruct.new(:contents => 'foo') expect(charset).to eq 'utf-8' end if YARD.ruby18? if YARD.ruby18? it "returns utf-8 if no LANG env is set" do expect(ENV).to receive(:[]).with('LANG').and_return(nil) expect(charset).to eq 'utf-8' end it "only returns charset part of lang" do expect(ENV).to receive(:[]).with('LANG').and_return('en_US.UTF-8') expect(charset).to eq 'utf-8' end end end describe "#format_types" do it "includes brackets by default" do text = ["String"] expect(self).to receive(:linkify).at_least(1).times.with("String", "String").and_return("String") expect(format_types(text)).to eq format_types(text, true) expect(format_types(text)).to eq "(String)" end it "avoids brackets if brackets=false" do expect(self).to receive(:linkify).with("String", "String").and_return("String") expect(self).to receive(:linkify).with("Symbol", "Symbol").and_return("Symbol") expect(format_types(["String", "Symbol"], false)).to eq "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 "links all classes in #{text}" do if text.count('<') > 0 expect(self).to receive(:h).with('<').at_least(text.count('<')).times.and_return("<") end if text.count('>') > 0 expect(self).to receive(:h).with('>').at_least(text.count('>')).times.and_return(">") end values[0].each {|v| expect(self).to receive(:linkify).with(v, v).and_return("#{v}") } expect(format_types([text], false)).to eq values[1] end end end describe "#htmlify" do it "does not use hard breaks for textile markup (RedCloth specific)" do begin; require 'redcloth'; rescue LoadError; pending 'test requires redcloth gem' end expect(htmlify("A\nB", :textile)).not_to include("", :pre)).to eq "
            fo\no\n\nbar<>
            " end it "returns regular text with :text markup" do expect(htmlify("fo\no\n\nbar<>", :text)).to eq "fo
            o

            bar<>" end it "returns unmodified text with :none markup" do expect(htmlify("fo\no\n\nbar<>", :none)).to eq "fo\no\n\nbar<>" end it "highlights ruby if markup is :ruby" do expect(htmlify("class Foo; end", :ruby)).to match(/\A
            HI

            " end it "allows inline includes for {include:} in the middle of a line" do load_markup_provider(:rdoc) expect(File).to receive(:file?).with('foo.rdoc').and_return(true) expect(File).to receive(:read).with('foo.rdoc').and_return('HI') expect(htmlify("test {include:file:foo.rdoc}", :rdoc).gsub(/[\r?\n]+/, '')).to eq '

            test HI

            ' end it "autolinks 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 expect(htmlify('http://example.com', :markdown).chomp.gsub('/', '/')).to eq( '

            http://example.com

            ' ) end it "does 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 expect(htmlify('{http://example.com Title}', :markdown).chomp).to match( %r{

            Title

            } ) expect(htmlify('{http://example.com}', :markdown).chomp).to match( %r{

            http://example.com

            } ) end it "creates tables (markdown specific)" do log.enter_level(Logger::FATAL) do supports_table = %w(RedcarpetCompat Kramdown::Document) unless supports_table.include?(markup_class(:markdown).to_s) pending "This test depends on a markdown engine that supports tables" end end markdown = <<-EOF.strip City | State | Country --------|-------|-------- Raleigh | NC | US Seattle | WA | US EOF html = htmlify(markdown, :markdown) expect(html).to match(//) expect(html).to match %r{} expect(html).to match %r{} end it "handles fenced code blocks (Redcarpet specific)" do log.enter_level(Logger::FATAL) do unless markup_class(:markdown).to_s == 'RedcarpetCompat' pending 'This test is Redcarpet specific' end end markdown = "Introduction:\n```ruby\nputs\n\nputs\n```" html = htmlify(markdown, :markdown) expect(html).to match %r{^

            Introduction:

            .*}m end end describe "#link_object" do let(:object) { CodeObjects::NamespaceObject.new(nil, :YARD) } it "returns the object path if there's no serializer and no title" do allow(self).to receive(:serializer).and_return(nil) expect(link_object(CodeObjects::NamespaceObject.new(nil, :YARD))).to eq "YARD" end it "returns the title if there's a title but no serializer" do allow(self).to receive(:serializer).and_return(nil) expect(link_object(CodeObjects::NamespaceObject.new(nil, :YARD), 'title')).to eq "title" end it "links 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) allow(self).to receive(:serializer).and_return(Serializers::FileSystemSerializer.new) allow(self).to receive(:object).and_return(obj) expect(link_object("Bar#a")).to match(/href="Bar.html#a-instance_method"/) end it "uses relative path in title" do CodeObjects::ModuleObject.new(:root, :YARD) CodeObjects::ClassObject.new(P('YARD'), :Bar) allow(self).to receive(:object).and_return(CodeObjects::ModuleObject.new(P('YARD'), :Foo)) allow(self).to receive(:serializer).and_return(Serializers::FileSystemSerializer.new) expect(link_object("Bar")).to match %r{>Bar} end it "uses #title if overridden" do CodeObjects::ModuleObject.new(:root, :YARD) CodeObjects::ClassObject.new(P('YARD'), :Bar) allow(Registry.at('YARD::Bar')).to receive(:title).and_return('TITLE!') allow(self).to receive(:object).and_return(Registry.at('YARD::Bar')) allow(self).to receive(:serializer).and_return(Serializers::FileSystemSerializer.new) expect(link_object("Bar")).to match %r{>TITLE!} end it "uses relative path to parent class in title" do root = CodeObjects::ModuleObject.new(:root, :YARD) obj = CodeObjects::ModuleObject.new(root, :SubModule) allow(self).to receive(:object).and_return(obj) allow(self).to receive(:serializer).and_return(Serializers::FileSystemSerializer.new) expect(link_object("YARD")).to match %r{>YARD} end it "uses Klass.foo when linking to class method in current namespace" do root = CodeObjects::ModuleObject.new(:root, :Klass) CodeObjects::MethodObject.new(root, :foo, :class) allow(self).to receive(:object).and_return(root) allow(self).to receive(:serializer).and_return(Serializers::FileSystemSerializer.new) expect(link_object("foo")).to match %r{>Klass.foo} end it "escapes method name in title" do YARD.parse_string <<-'eof' class Array def &(other) end end eof obj = Registry.at('Array#&') allow(self).to receive(:serializer).and_return(Serializers::FileSystemSerializer.new) allow(self).to receive(:object).and_return(obj) expect(link_object("Array#&")).to match(/title="Array#& \(method\)"/) end end describe "#url_for" do before { Registry.clear } it "returns nil if serializer is nil" do allow(self).to receive(:serializer).and_return nil allow(self).to receive(:object).and_return Registry.root expect(url_for(P("Mod::Class#meth"))).to be nil end it "returns nil if object is hidden" do yard = CodeObjects::ModuleObject.new(:root, :YARD) allow(self).to receive(:serializer).and_return(Serializers::FileSystemSerializer.new) allow(self).to receive(:object).and_return Registry.root allow(self).to receive(:options).and_return OpenStruct.new(:verifier => Verifier.new('false')) expect(url_for(yard)).to be nil end it "returns nil if serializer does not implement #serialized_path" do allow(self).to receive(:serializer).and_return Serializers::Base.new allow(self).to receive(:object).and_return Registry.root expect(url_for(P("Mod::Class#meth"))).to be nil end it "links to a path/file for a namespace object" do allow(self).to receive(:serializer).and_return Serializers::FileSystemSerializer.new allow(self).to receive(:object).and_return Registry.root yard = CodeObjects::ModuleObject.new(:root, :YARD) expect(url_for(yard)).to eq 'YARD.html' end it "links to the object's namespace path/file and use the object as the anchor" do allow(self).to receive(:serializer).and_return Serializers::FileSystemSerializer.new allow(self).to receive(:object).and_return Registry.root yard = CodeObjects::ModuleObject.new(:root, :YARD) meth = CodeObjects::MethodObject.new(yard, :meth) expect(url_for(meth)).to eq 'YARD.html#meth-instance_method' end it "properly urlencodes methods with punctuation in links" do obj = CodeObjects::MethodObject.new(nil, :/) serializer = double(:serializer, :serialized_path => "file.html") allow(self).to receive(:serializer).and_return serializer allow(self).to receive(:object).and_return obj expect(url_for(obj)).to eq "#%2F-instance_method" end end describe "#anchor_for" do it "does not urlencode data when called directly" do obj = CodeObjects::MethodObject.new(nil, :/) expect(anchor_for(obj)).to eq "/-instance_method" end end describe "#resolve_links" do def parse_link(link) results = {} link =~ %r{(.+?)}m params = $1 results[:inner_text] = $2 params.scan(/\s*(\S+?)=['"](.+?)['"]\s*/).each do |key, value| results[key.to_sym] = value.gsub(/^["'](.+)["']$/, '\1') end results end it "escapes {} syntax with backslash (\\{foo bar})" do input = '\{foo bar} \{XYZ} \{file:FOO} $\{N-M}' output = '{foo bar} {XYZ} {file:FOO} ${N-M}' expect(resolve_links(input)).to eq output end it "escapes {} syntax with ! (!{foo bar})" do input = '!{foo bar} !{XYZ} !{file:FOO} $!{N-M}' output = '{foo bar} {XYZ} {file:FOO} ${N-M}' expect(resolve_links(input)).to eq output end it "links static files with file: prefix" do allow(self).to receive(:serializer).and_return Serializers::FileSystemSerializer.new allow(self).to receive(:object).and_return Registry.root expect(parse_link(resolve_links("{file:TEST.txt#abc}"))).to eq( :inner_text => "TEST", :title => "TEST", :href => "file.TEST.html#abc" ) expect(parse_link(resolve_links("{file:TEST.txt title}"))).to eq( :inner_text => "title", :title => "title", :href => "file.TEST.html" ) end it "creates regular links with http:// or https:// prefixes" do expect(parse_link(resolve_links("{http://example.com}"))).to eq( :inner_text => "http://example.com", :target => "_parent", :href => "http://example.com", :title => "http://example.com" ) expect(parse_link(resolve_links("{http://example.com title}"))).to eq( :inner_text => "title", :target => "_parent", :href => "http://example.com", :title => "title" ) end it "creates mailto links with mailto: prefixes" do expect(parse_link(resolve_links('{mailto:joanna@example.com}'))).to eq( :inner_text => 'mailto:joanna@example.com', :target => '_parent', :href => 'mailto:joanna@example.com', :title => 'mailto:joanna@example.com' ) expect(parse_link(resolve_links('{mailto:steve@example.com Steve}'))).to eq( :inner_text => 'Steve', :target => '_parent', :href => 'mailto:steve@example.com', :title => 'Steve' ) end it "ignores {links} that begin with |...|" do expect(resolve_links("{|x|x == 1}")).to eq "{|x|x == 1}" end it "gracefully ignores {} in links" do allow(self).to receive(:linkify).with('Foo', 'Foo').and_return('FOO') expect(resolve_links("{} {} {Foo Foo}")).to eq '{} {} FOO' end %w(tt code pre).each do |tag| it "ignores links in <#{tag}>" do text = "<#{tag}>{Foo}" expect(resolve_links(text)).to eq text end end it "resolves {Name}" do expect(self).to receive(:link_file).with('TEST', nil, nil).and_return('') resolve_links("{file:TEST}") end it "resolves ({Name})" do expect(self).to receive(:link_file).with('TEST', nil, nil).and_return('') resolve_links("({file:TEST})") end it "resolves link with newline in title-part" do expect(parse_link(resolve_links("{http://example.com foo\nbar}"))).to eq( :inner_text => "foo bar", :target => "_parent", :href => "http://example.com", :title => "foo bar" ) end it "resolves links to methods whose names have been escaped" do expect(self).to receive(:linkify).with('Object#<<', nil).and_return('') resolve_links("{Object#<<}") end it "warns 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 = double(:log) expect(logger).to receive(:warn).ordered.with( "In file `(stdin)':2: Cannot resolve link to InvalidObject from text:\n\t...{InvalidObject}" ) allow(self).to receive(:log).and_return(logger) allow(self).to receive(:object).and_return(Registry.at('MyObject')) resolve_links(object.docstring) end it "shows 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 = double(:log) expect(logger).to receive(:warn).ordered.with("In file `(stdin)':1: Cannot resolve link to InvalidObject1 from text:\n\t{InvalidObject1}...") expect(logger).to receive(:warn).ordered.with("In file `(stdin)':2: Cannot resolve link to InvalidObject2 from text:\n\t...{InvalidObject2}") expect(logger).to receive(:warn).ordered.with("In file `(stdin)':3: Cannot resolve link to InvalidObject3 from text:\n\t...{InvalidObject3}...") expect(logger).to receive(:warn).ordered.with("In file `(stdin)':4: Cannot resolve link to InvalidObject4 from text:\n\t{InvalidObject4}") allow(self).to receive(:log).and_return(logger) allow(self).to receive(:object).and_return(Registry.at('MyObject')) resolve_links(object.docstring) end it "warns about missing reference for file template (no object)" do @file = CodeObjects::ExtraFileObject.new('myfile.txt', '') logger = double(:log) expect(logger).to receive(:warn).ordered.with("In file `myfile.txt':3: Cannot resolve link to InvalidObject from text:\n\t...{InvalidObject Some Title}") allow(self).to receive(:log).and_return(logger) allow(self).to receive(: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 arrow = "⇒" @results = { :regular => "#foo #{arrow} Object", :default_return => "#foo #{arrow} Hello", :no_default_return => "#foo", :private_class => ".foo #{arrow} Object (private)", :single => "#foo #{arrow} String", :two_types => "#foo #{arrow} String, Symbol", :two_types_multitag => "#foo #{arrow} String, Symbol", :type_nil => "#foo #{arrow} Type?", :type_array => "#foo #{arrow} Type+", :multitype => "#foo #{arrow} Type, ...", :void => "#foo #{arrow} void", :hide_void => "#foo", :block => "#foo {|a, b, c| ... } #{arrow} Object", :empty_overload => "#foobar #{arrow} String" } 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 "links 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 = double(:serializer) allow(serializer).to receive(:serialized_path).with(Registry.at('Foo')).and_return('') allow(self).to receive(:serializer).and_return(serializer) allow(self).to receive(:object).and_return(Registry.at('Foo')) expect(signature(Registry.at('Foo#foo').tag(:overload), true)).to eq( "#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 "returns empty string on nil input" do expect(subject.html_syntax_highlight(nil)).to eq '' end it "calls #html_syntax_highlight_ruby by default" do Registry.root.source_type = nil expect(subject).to receive(:html_syntax_highlight_ruby).with('def x; end') subject.html_syntax_highlight('def x; end') end it "calls #html_syntax_highlight_NAME if there's an object with a #source_type" do subject.object = OpenStruct.new(:source_type => :NAME) expect(subject).to receive(:html_markup_html) {|text| text } expect(subject).to receive(:html_syntax_highlight_NAME).and_return("foobar") expect(subject.htmlify('
            def x; end
            ', :html)).to eq( '
            foobar
            ' ) end it "adds !!!LANG to className in outputted pre tag" do subject.object = OpenStruct.new(:source_type => :LANG) expect(subject).to receive(:html_markup_html) {|text| text } expect(subject).to receive(:html_syntax_highlight_LANG).and_return("foobar") expect(subject.htmlify("
            !!!LANG\ndef x; end
            ", :html)).to eq( '
            foobar
            ' ) end it "calls html_syntax_highlight_NAME if source starts with !!!NAME" do expect(subject).to receive(:html_syntax_highlight_NAME).and_return("foobar") expect(subject.html_syntax_highlight(<<-eof !!!NAME def x; end eof )).to eq "foobar" end it "does not highlight if highlight option is false" do subject.options.highlight = false expect(subject).not_to receive(:html_syntax_highlight_ruby) expect(subject.html_syntax_highlight('def x; end')).to eq 'def x; end' end it "does not highlight if there is no highlight method specified by !!!NAME" do def subject.respond_to?(method, include_all = false) return false if method == 'html_syntax_highlight_NAME' super end expect(subject).not_to receive(:html_syntax_highlight_NAME) expect(subject.html_syntax_highlight("!!!NAME\ndef x; end")).to eq "def x; end" end it "highlights as ruby if htmlify(text, :ruby) is called" do expect(subject).to receive(:html_syntax_highlight_ruby).with('def x; end').and_return('x') expect(subject.htmlify('def x; end', :ruby)).to eq '
            x
            ' end it "does not prioritize object source type when called directly" do expect(subject).to receive(:html_syntax_highlight_ruby).with('def x; end').and_return('x') subject.object = OpenStruct.new(:source_type => :c) expect(subject.html_syntax_highlight("def x; end")).to eq "x" end it "doesn't escape code snippets twice" do expect(subject.htmlify('
            {"foo" => 1}
            ', :html)).to eq( '
            {"foo" => 1}
            ' ) end it "highlights source when matching a pre lang= tag" do expect(subject.htmlify('
            x = 1
            ', :html)).to eq( '
            x = 1
            ' ) end it "highlights source when matching a code class= tag" do expect(subject.htmlify('
            x = 1
            ', :html)).to eq( '
            x = 1
            ' ) end end describe "#link_url" do it "adds target if scheme is provided" do expect(link_url("http://url.com")).to include(" target=\"_parent\"") expect(link_url("https://url.com")).to include(" target=\"_parent\"") expect(link_url("irc://url.com")).to include(" target=\"_parent\"") expect(link_url("../not/scheme")).not_to include("target") end end end yard-0.9.12/spec/templates/helpers/base_helper_spec.rb0000755000004100000410000001342013206751010022772 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::Templates::Helpers::BaseHelper do include YARD::Templates::Helpers::BaseHelper describe "#run_verifier" do it "runs verifier proc against list if provided" do mock = Verifier.new expect(mock).to receive(:call).with(1) expect(mock).to receive(:call).with(2) expect(mock).to receive(:call).with(3) expect(self).to receive(:options).at_least(1).times.and_return(Options.new.update(:verifier => mock)) run_verifier [1, 2, 3] end it "prunes list if lambda returns false and only false" do mock = Verifier.new expect(self).to receive(:options).at_least(1).times.and_return(Options.new.update(:verifier => mock)) expect(mock).to receive(:call).with(1).and_return(false) expect(mock).to receive(:call).with(2).and_return(true) expect(mock).to receive(:call).with(3).and_return(nil) expect(mock).to receive(:call).with(4).and_return("value") expect(run_verifier([1, 2, 3, 4])).to eq [2, 3, 4] end it "returns list if no verifier exists" do expect(self).to receive(:options).at_least(1).times.and_return(Options.new) expect(run_verifier([1, 2, 3])).to eq [1, 2, 3] end end describe "#h" do it "returns just the text" do expect(h("hello world")).to eq "hello world" expect(h(nil)).to eq nil end end describe "#link_object" do it "returns the title if provided" do expect(link_object(1, "title")).to eq "title" expect(link_object(Registry.root, "title")).to eq "title" end it "returns a path if argument is a Proxy or object" do expect(link_object(Registry.root)).to eq "Top Level Namespace" expect(link_object(P("Array"))).to eq "Array" end it "returns path of Proxified object if argument is a String or Symbol" do expect(link_object("Array")).to eq "Array" expect(link_object(:"A::B")).to eq "A::B" end it "returns the argument if not an object, proxy, String or Symbol" do expect(link_object(1)).to eq 1 end end describe "#link_url" do it "returns the URL" do expect(link_url("http://url")).to eq "http://url" end end describe "#linkify" do let(:object) { Registry.root } # before do # stub!(:object).and_return(Registry.root) # end it "calls #link_url for mailto: links" do expect(self).to receive(:link_url) linkify("mailto:steve@example.com") end it "calls #link_url for URL schemes (http://)" do expect(self).to receive(:link_url) linkify("http://example.com") end it "calls #link_file for file: links" do expect(self).to receive(:link_file).with('Filename', nil, 'anchor') linkify("file:Filename#anchor") end it "passes off to #link_object if argument is an object" do obj = CodeObjects::NamespaceObject.new(nil, :YARD) expect(self).to receive(:link_object).with(obj) linkify obj end it "returns empty string and warn if object does not exist" do expect(log).to receive(:warn).with(/Cannot find object .* for inclusion/) expect(linkify('include:NotExist')).to eq '' end it "passes off to #link_url if argument is recognized as a URL" do url = "http://yardoc.org/" expect(self).to receive(:link_url).with(url, nil, :target => '_parent') linkify url end it "calls #link_include_object for include:ObjectName" do obj = CodeObjects::NamespaceObject.new(:root, :Foo) expect(self).to receive(:link_include_object).with(obj) linkify 'include:Foo' end it "calls #link_include_file for include:file:path/to/file" do expect(File).to receive(:file?).with('path/to/file').and_return(true) expect(File).to receive(:read).with('path/to/file').and_return('FOO') expect(linkify('include:file:path/to/file')).to eq 'FOO' end it "does not allow include:file for path above pwd" do expect(log).to receive(:warn).with("Cannot include file from path `a/b/../../../../file'") expect(linkify('include:file:a/b/../../../../file')).to eq '' end it "warns if include:file:path does not exist" do expect(log).to receive(:warn).with(/Cannot find file .+ for inclusion/) expect(linkify('include:file:notexist')).to eq '' end end describe "#format_types" do it "returns the list of types separated by commas surrounded by brackets" do expect(format_types(['a', 'b', 'c'])).to eq '(a, b, c)' end it "returns the list of types without brackets if brackets=false" do expect(format_types(['a', 'b', 'c'], false)).to eq 'a, b, c' end it "returns an empty string if list is empty or nil" do expect(format_types(nil)).to eq "" expect(format_types([])).to eq "" end end describe "#format_object_type" do it "returns Exception if type is Exception" do obj = double(:object, :is_exception? => true) allow(obj).to receive(:is_a?) {|arg| arg == YARD::CodeObjects::ClassObject } expect(format_object_type(obj)).to eq "Exception" end it "returns Class if type is Class" do obj = double(:object, :is_exception? => false) allow(obj).to receive(:is_a?) {|arg| arg == YARD::CodeObjects::ClassObject } expect(format_object_type(obj)).to eq "Class" end it "returns object type in other cases" do obj = double(:object, :type => "value") expect(format_object_type(obj)).to eq "Value" end end describe "#format_object_title" do it "returns Top Level Namespace for root object" do expect(format_object_title(Registry.root)).to eq "Top Level Namespace" end it "returns 'type: title' in other cases" do obj = double(:object, :type => :class, :title => "A::B::C") expect(format_object_title(obj)).to eq "Class: A::B::C" end end end yard-0.9.12/spec/templates/helpers/html_syntax_highlight_helper_spec.rb0000755000004100000410000000631113206751010026462 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::Templates::Helpers::HtmlSyntaxHighlightHelper do include YARD::Templates::Helpers::HtmlHelper include YARD::Templates::Helpers::HtmlSyntaxHighlightHelper describe "#html_syntax_highlight" do let(:object) { CodeObjects::NamespaceObject.new(:root, :YARD) } before do Registry.root.source_type = :ruby end it "does not highlight source if options.highlight is false" do expect(self).to receive(:options).and_return(Options.new.update(:highlight => false)) expect(html_syntax_highlight("def x\nend")).to eq "def x\nend" end it "highlights source (legacy)" do type = Parser::SourceParser.parser_type Parser::SourceParser.parser_type = :ruby18 expect(self).to 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 "highlights source (ripper)" do expect(self).to 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 "returns escaped unhighlighted source if a syntax error is found (ripper)" do allow(self).to receive(:options).and_return(Options.new.update(:highlight => true)) expect(html_syntax_highlight("def &x; ... end")).to eq "def &x; ... end" end if HAVE_RIPPER it "returns escaped unhighlighted source if a syntax error is found (ripper)" do allow(self).to receive(:options).and_return(Options.new.update(:highlight => true)) expect(html_syntax_highlight("$ git clone http://url")).to eq "$ git clone http://url" end if HAVE_RIPPER it "links constants/methods" do other = CodeObjects::NamespaceObject.new(:root, :Other) allow(self).to receive(:options).and_return(Options.new.update(:highlight => true)) allow(self).to receive(:run_verifier).with([other]).and_return([other]) allow(self).to receive(:link_object).with(other, "Other").and_return("LINK!") result = html_syntax_highlight("def x; Other end") html_equals_string(result, "def x; LINK! end") end if HAVE_RIPPER end end yard-0.9.12/spec/templates/helpers/text_helper_spec.rb0000755000004100000410000000372013206751010023046 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + "/shared_signature_examples" RSpec.describe YARD::Templates::Helpers::TextHelper do include YARD::Templates::Helpers::BaseHelper 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 "aligns text right" do text = "Method: #some_method (SomeClass)" expect(align_right(text)).to eq ' ' * 40 + text end it "truncates text that is longer than allowed width" do text = "(Defined in: /home/user/.rip/.packages/some_gem-2460672e333ac07b9190ade88ec9a91c/long/path.rb)" expect(align_right(text)).to eq ' ' + text[0, 68] + '...' end end describe "#h" do let(:object) do YARD::CodeObjects::MethodObject.new(:root, :foo, :instance).tap do |o| o.docstring = "test" end end it "resolves links" do expect(h("{include:#foo} 1 2 3").strip).to eq "test 1 2 3" end it "uses title when present" do expect(h("{A b}").strip).to eq "b" end it "uses object name when no title is present" do expect(h("{A}").strip).to eq "A" end end end yard-0.9.12/spec/templates/template_spec.rb0000755000004100000410000003210213206751010020670 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.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 "does not include parent directory if parent directory is a template root path" do mod = template('q') expect(mod).not_to include(template('')) end it "includes overridden parent directory" do allow(Engine).to receive(:template_paths).and_return(['/foo', '/bar']) expect(File).to receive(:directory?).with('/foo/a/b').and_return(true) expect(File).to receive(:directory?).with('/bar/a/b').and_return(false) expect(File).to receive(:directory?).with('/foo/a').at_least(1).times.and_return(true) expect(File).to receive(:directory?).with('/bar/a').at_least(1).times.and_return(true) ancestors = Engine.template('a/b').ancestors.map(&:class_name) expect(ancestors[0, 3]).to eq %w(Template__foo_a_b Template__bar_a Template__foo_a) end it "includes parent directory template if exists" do mod1 = template('x') mod2 = template('x/y') expect(mod2).to include(mod1) end end describe ".full_paths" do it "lists full_path" do mod = template(:a) expect(mod.full_paths).to eq ['/full/path/a'] end it "lists paths of included modules" do mod = template(:a) mod.send(:include, template(:b)) expect(mod.full_paths).to eq ['/full/path/a', '/full/path/b'] end it "lists paths from modules of included modules" do mod = template(:c) mod.send(:include, template(:d)) mod.send(:include, template(:a)) expect(mod.full_paths).to eq ['c', 'a', 'b', 'd'].map {|o| '/full/path/' + o } end it "only lists full paths of modules that respond to full_paths" do mod = template(:d) mod.send(:include, Enumerable) expect(mod.full_paths).to eq ['/full/path/d'] end end describe ".load_setup_rb" do it "loads setup.rb file for module" do expect(File).to receive(:file?).with('/full/path/e/setup.rb').and_return(true) expect(File).to receive(:read).with('/full/path/e/setup.rb').and_return(String.new('def success; end')) expect(template(:e).new).to respond_to(:success) end end describe ".T" do it "loads template from absolute path" do mod = template(:a) expect(Engine).to receive(:template).with('other') mod.T('other') end end describe ".find_file" do it "finds file in the module's full_path" do expect(File).to receive(:file?).with('/full/path/a/basename').and_return(false) expect(File).to receive(:file?).with('/full/path/b/basename').and_return(true) expect(template(:a).find_file('basename')).to eq '/full/path/b/basename' end it "returns nil if no file is found" do expect(File).to receive(:file?).with('/full/path/a/basename').and_return(false) expect(File).to receive(:file?).with('/full/path/b/basename').and_return(false) expect(template(:a).find_file('basename')).to be nil end end describe ".find_nth_file" do it "finds 2nd existing file in template paths" do expect(File).to receive(:file?).with('/full/path/a/basename').and_return(true) expect(File).to receive(:file?).with('/full/path/b/basename').and_return(true) expect(template(:a).find_nth_file('basename', 2)).to eq '/full/path/b/basename' end it "returns nil if no file is found" do expect(File).to receive(:file?).with('/full/path/a/basename').and_return(true) expect(File).to receive(:file?).with('/full/path/b/basename').and_return(true) expect(template(:a).find_nth_file('basename', 3)).to be nil end end describe ".extra_includes" do it "is included when a module is initialized" do module MyModule; end Template.extra_includes << MyModule expect(template(:e).new).to be_kind_of(MyModule) end it "supports lambdas in list" do module MyModule2; end Template.extra_includes << lambda {|opts| MyModule2 if opts.format == :html } expect(template(:f).new(:format => :html)).to be_kind_of(MyModule2) metaclass = (class << template(:g).new(:format => :text); self end) expect(metaclass.ancestors).not_to include(MyModule2) end end describe ".is_a?" do it "is kind of Template" do expect(template(:e).is_a?(Template)).to be true end end describe "#T" do it "delegates to class method" do expect(template(:e)).to receive(:T).with('test') template(:e).new.T('test') end end describe "#init" do it "is called during initialization" do module YARD::Templates::Engine::Template__full_path_e # rubocop:disable Style/ClassAndModuleCamelCase def init; sections 1, 2, 3 end end expect(template(:e).new.sections).to eq Section.new(nil, 1, 2, 3) end end describe "#file" do it "reads the file if it exists" do expect(File).to receive(:file?).with('/full/path/e/abc').and_return(true) expect(IO).to receive(:read).with('/full/path/e/abc').and_return('hello world') expect(template(:e).new.file('abc')).to eq 'hello world' end it "raises ArgumentError if the file does not exist" do expect(File).to receive(:file?).with('/full/path/e/abc').and_return(false) expect { template(:e).new.file('abc') }.to raise_error(ArgumentError) end it "replaces {{{__super__}}} with inherited template contents if allow_inherited=true" do expect(File).to receive(:file?).with('/full/path/a/abc').twice.and_return(true) expect(File).to receive(:file?).with('/full/path/b/abc').and_return(true) expect(IO).to receive(:read).with('/full/path/a/abc').and_return(String.new('foo {{{__super__}}}')) expect(IO).to receive(:read).with('/full/path/b/abc').and_return(String.new('bar')) expect(template(:a).new.file('abc', true)).to eq "foo bar" end it "does not replace {{{__super__}}} with inherited template contents if allow_inherited=false" do expect(File).to receive(:file?).with('/full/path/a/abc').and_return(true) expect(IO).to receive(:read).with('/full/path/a/abc').and_return('foo {{{__super__}}}') expect(template(:a).new.file('abc')).to eq "foo {{{__super__}}}" end end describe "#superb" do it "returns the inherited erb template contents" do expect(File).to receive(:file?).with('/full/path/a/test.erb').and_return(true) expect(File).to receive(:file?).with('/full/path/b/test.erb').and_return(true) expect(IO).to receive(:read).with('/full/path/b/test.erb').and_return('bar') template = template(:a).new template.section = :test expect(template.superb).to eq "bar" end it "works inside an erb template" do expect(File).to receive(:file?).with('/full/path/a/test.erb').twice.and_return(true) expect(File).to receive(:file?).with('/full/path/b/test.erb').and_return(true) expect(IO).to receive(:read).with('/full/path/a/test.erb').and_return('foo<%= superb %>!') expect(IO).to receive(:read).with('/full/path/b/test.erb').and_return('bar') template = template(:a).new template.section = :test expect(template.erb(:test)).to eq "foobar!" end end describe "#sections" do it "allows sections to be set if arguments are provided" do mod = template(:e).new mod.sections 1, 2, [3] expect(mod.sections).to eq Section.new(nil, 1, 2, [3]) end end describe "#run" do it "renders all sections" do mod = template(:e).new allow(mod).to receive(:render_section) {|section| section.name.to_s } mod.sections :a, :b, :c expect(mod.run).to eq 'abc' end it "renders all sections with options" do mod = template(:e).new allow(mod).to receive(:render_section) {|section| section.name.to_s } expect(mod).to receive(:add_options).with(:a => 1).and_yield mod.sections :a expect(mod.run(:a => 1)).to eq 'a' end it "runs section list if provided" do mod = template(:e).new expect(mod).to receive(:render_section).exactly(2).times do |section| expect([:q, :x]).to include(section.name) section.name.to_s end mod.run({}, [:q, :x]) end it "accepts a nil section as empty string" do mod = template(:e).new allow(mod).to receive(:render_section) { nil } mod.sections :a expect(mod.run).to eq "" end end describe "#add_options" do it "sets instance variables in addition to options" do mod = template(:f).new mod.send(:add_options, :a => 1, :b => 2) expect(mod.options).to eq(:a => 1, :b => 2) expect(mod.instance_variable_get("@a")).to eq 1 expect(mod.instance_variable_get("@b")).to eq 2 end it "sets instance variables and options only for the block" do mod = template(:f).new mod.send(:add_options, :a => 100, :b => 200) do expect(mod.options).to eq(:a => 100, :b => 200) end expect(mod.options).not_to eq(:a => 100, :b => 200) end end describe "#render_section" do it "calls method if method exists by section name as Symbol" do mod = template(:f).new expect(mod).to receive(:respond_to?).with(:a).and_return(true) expect(mod).to receive(:respond_to?).with('a').and_return(true) expect(mod).to receive(:send).with(:a).and_return('a') expect(mod).to receive(:send).with('a').and_return('a') expect(mod.run({}, [:a, 'a'])).to eq 'aa' end it "calls erb if no method exists by section name" do mod = template(:f).new expect(mod).to receive(:respond_to?).with(:a).and_return(false) expect(mod).to receive(:respond_to?).with('a').and_return(false) expect(mod).to receive(:erb).with(:a).and_return('a') expect(mod).to receive(:erb).with('a').and_return('a') expect(mod.run({}, [:a, 'a'])).to eq 'aa' end it "runs a template if section is one" do mod2 = template(:g) expect(mod2).to receive(:run) mod = template(:f).new mod.sections mod2 mod.run end it "runs a template instance if section is one" do mod2 = template(:g).new expect(mod2).to receive(:run) mod = template(:f).new mod.sections mod2 mod.run end end describe "#yield" do it "yields 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 expect(mod.run).to eq "(b)" end it "yields 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 expect(mod.run).to eq "(c)" end it "supports 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 expect(mod.run).to eq "(e)" end it "yields 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 expect(mod.run).to eq "(bc)" end it "ignores 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 expect(mod.run).to eq "(bd)" end it "allows 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 expect(mod.run).to eq "(aa)" end end describe "#yieldall" do it "yields 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 expect(mod.run).to eq "(bdec)" end it "yields 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 expect(mod.run).to eq "(22)" end it "yields 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 expect(mod.run).to eq "(bb)" end it "does 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 expect(mod.run).to eq "()" end end end yard-0.9.12/spec/templates/engine_spec.rb0000755000004100000410000001143213206751010020325 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe YARD::Templates::Engine do before { @paths = Engine.template_paths } after { Engine.template_paths = @paths } describe ".register_template_path" do it "registers a String path" do Engine.register_template_path('.') expect(Engine.template_paths.pop).to eq '.' end it "does not duplicate paths" do Engine.template_paths = [] Engine.register_template_path('foo') Engine.register_template_path('foo') expect(Engine.template_paths).to eq ['foo'] end end describe ".template!" do it "creates a module including Template" do mod = Engine.template!('path/to/template') expect(mod).to include(Template) expect(mod.full_path.to_s).to eq 'path/to/template' end it "creates a module including Template with full_path" do mod = Engine.template!('path/to/template2', '/full/path/to/template2') expect(mod).to include(Template) expect(mod.full_path.to_s).to eq '/full/path/to/template2' end end describe ".template" do it "raises an error if the template is not found" do expect { Engine.template(:a, :b, :c) }.to raise_error(ArgumentError) end it "creates a module including Template" do mock = double(:template) expect(Engine).to receive(:find_template_paths).with(nil, 'template/name').and_return(['/full/path/template/name']) expect(Engine).to receive(:template!).with('template/name', ['/full/path/template/name']).and_return(mock) expect(Engine.template('template/name')).to eq mock end it "creates a Template from a relative Template path" do expect(Engine).to receive(:template_paths).and_return([]) expect(File).to receive(:directory?).with("/full/path/template/notname").and_return(true) start_template = double(:start_template, :full_path => '/full/path/template/name', :full_paths => ['/full/path/template/name']) expect(start_template).to receive(:is_a?).with(Template).and_return(true) mod = Engine.template(start_template, '..', 'notname') expect(mod).to include(Template) expect(mod.full_path.to_s).to eq "/full/path/template/notname" end it "creates a Template including other matching templates in path" do paths = ['/full/path/template/name', '/full/path2/template/name'] expect(Engine).to receive(:find_template_paths).with(nil, 'template').at_least(1).times.and_return([]) expect(Engine).to receive(:find_template_paths).with(nil, 'template/name').and_return(paths) ancestors = Engine.template('template/name').ancestors.map(&:class_name) expect(ancestors).to include("Template__full_path2_template_name") end it "includes parent directories before other template paths" do paths = ['/full/path/template/name', '/full/path2/template/name'] expect(Engine).to receive(:find_template_paths).with(nil, 'template/name').and_return(paths) ancestors = Engine.template('template/name').ancestors.map(&:class_name) expect(ancestors[0, 4]).to eq ["Template__full_path_template_name", "Template__full_path_template", "Template__full_path2_template_name", "Template__full_path2_template"] end end describe ".generate" do it "generates with fulldoc template" do mod = double(:template) options = TemplateOptions.new options.reset_defaults options.objects = [:a, :b, :c] options.object = Registry.root expect(mod).to receive(:run).with(options) expect(Engine).to receive(:template).with(:default, :fulldoc, :text).and_return(mod) Engine.generate([:a, :b, :c]) end end describe ".render" do def loads_template(*args) expect(Engine).to 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 = double(:template, :include => nil) expect(@template).to receive(:run).with(@options) end it "accepts method call with no parameters" do loads_template(:default, :method, :text) @object.format end it "allows template key to be changed" do loads_template(:javadoc, :method, :text) @options.template = :javadoc @object.format(:template => :javadoc) end it "allows type key to be changed" do loads_template(:default, :fulldoc, :text) @options.type = :fulldoc @object.format(:type => :fulldoc) end it "allows format key to be changed" do loads_template(:default, :method, :html) @options.format = :html @object.format(:format => :html) end end end yard-0.9.12/spec/templates/tag_spec.rb0000755000004100000410000000266013206751010017636 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.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 "renders text format correctly" do text_equals(Registry.at('#m').format(text_options), :tag001) end end describe "param tags on non-methods" do it "does 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) } expect(proc).not_to raise_error end end end yard-0.9.12/spec/rubygems/0000755000004100000410000000000013206751010015354 5ustar www-datawww-datayard-0.9.12/spec/rubygems/doc_manager_spec.rb0000755000004100000410000000734413206751010021165 0ustar www-datawww-data# frozen_string_literal: true require File.join(YARD::ROOT, 'rubygems_plugin') require 'fileutils' RSpec.describe Gem::DocManager do before do # Ensure filesystem integrity allow(FileUtils).to receive(:mkdir_p) allow(FileUtils).to receive(:rm_rf) allow(Dir).to receive(:chdir) allow(YARD::CLI::Yardoc).to receive(: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) allow(@doc).to receive(:install_ri_yard_orig) allow(@doc).to receive(:install_rdoc_yard_orig) end def runs; expect(YARD::CLI::Yardoc).to receive(:run) end describe ".load_yardoc" do it "properly loads YARD" do expect(Gem::DocManager).to receive(:require) do |path| expect(File.expand_path(path)).to eq 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}..." expect(@doc).to receive(:say).with(msg) @doc.install_ri_yard end it "passes --quiet to all documentation" do runs.with('-c', '-n', '--quiet', 'lib') install end it "passes extra_rdoc_files to documentation" do @spec.extra_rdoc_files = %w(README LICENSE) runs.with('-c', '-n', '--quiet', 'lib', '-', 'README', 'LICENSE') install end it "adds --backtrace if Gem.configuration.backtrace" do Gem.configuration.backtrace = true runs.with('-c', '-n', '--quiet', '--backtrace', 'lib') install Gem.configuration.backtrace = false end it "adds require_paths if there is no .yardopts" do expect(File).to receive(:file?).with(@yardopts).and_return(true) runs.with('-c', '-n', '--quiet') install end it "adds extra_rdoc_files if there is no .yardopts" do @spec.extra_rdoc_files = %w(README LICENSE) expect(File).to receive(:file?).with(@yardopts).and_return(true) runs.with('-c', '-n', '--quiet') install end it "switches to directory before running command" do old = Dir.pwd expect(Dir).to receive(:chdir).with(@spec.full_gem_path) expect(Dir).to receive(:chdir).with(old) install end it "ensures that directory is switched back at end of command in failure" do old = Dir.pwd expect(Dir).to receive(:chdir).with(@spec.full_gem_path) expect(Dir).to receive(:chdir).with(old) expect(@doc.ui.errs).to receive(:puts).with(/ERROR:\s*While generating documentation/) expect(@doc.ui.errs).to receive(:puts).with(/MESSAGE:\s*foo/) expect(@doc.ui.errs).to receive(:puts).with(/YARDOC args:\s*-c -n --quiet lib/) expect(@doc.ui.errs).to receive(:puts).with("(continuing with the rest of the installation)") expect(YARD::CLI::Yardoc).to receive(:run).and_raise(RuntimeError.new("foo")) install end it "handles permission errors" do expect(YARD::CLI::Yardoc).to receive(:run).and_raise(Errno::EACCES.new("- dir")) expect { install }.to raise_error(Gem::FilePermissionError) end end describe "#install_rdoc_yard" do def install msg = "Installing YARD documentation for #{@spec.full_name}..." expect(@doc).to receive(:say).with(msg) @doc.install_rdoc_yard end it "adds -o outdir when generating docs" do expect(File).to 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.9.12/spec/rake/0000755000004100000410000000000013206751010014441 5ustar www-datawww-datayard-0.9.12/spec/rake/yardoc_task_spec.rb0000755000004100000410000000613013206751010020306 0ustar www-datawww-data# frozen_string_literal: true RSpec.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 allow(Templates::Engine).to receive(:render) allow(Templates::Engine).to receive(:generate) allow(YARD).to receive(:parse) allow(Registry).to receive(:load) allow(Registry).to receive(:save) allow(YARD::CLI::Yardoc).to receive(:new).and_return(@yardoc) ::Rake.application.clear end def run ::Rake.application.tasks[0].invoke end describe "#initialize" do it "allows separate rake task name to be set" do YARD::Rake::YardocTask.new(:notyardoc) expect(::Rake.application.tasks[0].name).to eq "notyardoc" end end describe "#files" do it "allows files to be set" do YARD::Rake::YardocTask.new do |t| t.files = ['a', 'b', 'c'] end run expect(@yardoc.files).to eq %w(a b c) end end describe "#options" do it "allows extra options to be set" do YARD::Rake::YardocTask.new do |t| t.options = ['--private', '--protected'] end run expect(@yardoc.visibilities).to eq [:public, :private, :protected] end it "allows --api and --no-api" do YARD::Rake::YardocTask.new do |t| t.options = %w(--api public --no-api) end run expect(@yardoc.options.verifier.expressions).to include('["public"].include?(@api.text) || !@api') end end describe "#stats_options" do before do @yard_stats = Object.new allow(@yard_stats).to receive(:run) allow(YARD::CLI::Stats).to receive(:new).and_return(@yard_stats) end it "invokes stats" do expect(@yard_stats).to receive(:run).with('--list-undoc', '--use-cache') @yardoc.statistics = true YARD::Rake::YardocTask.new do |t| t.stats_options = %w(--list-undoc) end run expect(@yardoc.statistics).to be false end end describe "#before" do it "allows before callback" do proc = lambda {} expect(proc).to receive(:call) expect(@yardoc).to receive(:run) YARD::Rake::YardocTask.new {|t| t.before = proc } run end end describe "#after" do it "allows after callback" do proc = lambda {} expect(proc).to receive(:call) expect(@yardoc).to receive(:run) YARD::Rake::YardocTask.new {|t| t.after = proc } run end end describe "#verifier" do it "allows a verifier proc to be set" do verifier = Verifier.new expect(@yardoc).to receive(:run) do expect(@yardoc.options[:verifier]).to eq verifier end YARD::Rake::YardocTask.new {|t| t.verifier = verifier } run end it "overrides --query options" do verifier = Verifier.new expect(@yardoc).to receive(:run) do expect(@yardoc.options[:verifier]).to eq verifier end YARD::Rake::YardocTask.new do |t| t.options += ['--query', '@return'] t.verifier = verifier end run end end end yard-0.9.12/spec/docstring_spec.rb0000755000004100000410000002774613206751010017075 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::Docstring do before { YARD::Registry.clear } describe "#initialize" do it "handles docstrings with empty newlines" do expect(Docstring.new("\n\n")).to eq "" end end describe "#+" do it "adds another Docstring" do d = Docstring.new("FOO") + Docstring.new("BAR") expect(d).to eq "FOO\nBAR" end it "copies over tags" do d1 = Docstring.new("FOO\n@api private\n") d2 = Docstring.new("BAR\n@param foo descr") d = (d1 + d2) expect(d).to have_tag(:api) expect(d).to have_tag(:param) end it "adds a String" do d = Docstring.new("FOO") + "BAR" expect(d).to eq "FOOBAR" end end describe "#line" do it "returns nil if #line_range is not set" do expect(Docstring.new('foo').line).to be nil end it "returns line_range.first if #line_range is set" do doc = Docstring.new('foo') doc.line_range = (1..10) expect(doc.line).to eq doc.line_range.first end end describe "#summary" do it "handles empty docstrings" do o1 = Docstring.new expect(o1.summary).to eq "" end it "handles multiple calls" do o1 = Docstring.new("Hello. world") 5.times { expect(o1.summary).to eq "Hello." } end it "strips newlines in first paragraph before summarizing" do doc = Docstring.new("Foo\n== bar.") expect(doc.summary).to eq 'Foo == bar.' end it "returns the first sentence" do o = Docstring.new("DOCSTRING. Another sentence") expect(o.summary).to eq "DOCSTRING." end it "returns the first paragraph" do o = Docstring.new("DOCSTRING, and other stuff\n\nAnother sentence.") expect(o.summary).to eq "DOCSTRING, and other stuff." end it "returns proper summary when docstring is changed" do o = Docstring.new "DOCSTRING, and other stuff\n\nAnother sentence." expect(o.summary).to eq "DOCSTRING, and other stuff." o = Docstring.new "DOCSTRING." expect(o.summary).to eq "DOCSTRING." end it "does 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") expect(o.summary).to eq "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 expect(doc.summary).to eq "Returns a list of tags specified by +name+ or all tags if +name+ is not specified." end it "does not attach period if entire summary is include" do YARD.parse_string "# docstring\ndef foo; end" expect(Docstring.new("{include:#foo}").summary).to eq '{include:#foo}' Registry.clear end it "handles references embedded in summary" do expect(Docstring.new("Aliasing {Test.test}. Done.").summary).to eq "Aliasing {Test.test}." end it "only ends first sentence when outside parentheses" do expect(Docstring.new("Hello (the best.) world. Foo bar.").summary).to eq "Hello (the best.) world." expect(Docstring.new("A[b.]c.").summary).to eq "A[b.]c." end it "only sees '.' as period if whitespace (or eof) follows" do expect(Docstring.new("hello 1.5 times.").summary).to eq "hello 1.5 times." expect(Docstring.new("hello... me").summary).to eq "hello..." expect(Docstring.new("hello.").summary).to eq "hello." end it "returns summary if there is a newline and parentheses count doesn't match" do expect(Docstring.new("Happy method call :-)\n\nCall any time.").summary).to eq "Happy method call :-)." expect(Docstring.new("Sad method call :-(\n\nCall any time.").summary).to eq "Sad method call :-(." expect(Docstring.new("Hello (World. Forget to close.\n\nNew text").summary).to eq "Hello (World. Forget to close." expect(Docstring.new("Hello (World. Forget to close\n\nNew text").summary).to eq "Hello (World. Forget to close." end end describe "#ref_tags" do it "parses reference tag into ref_tags" do doc = Docstring.new("@return (see Foo#bar)") expect(doc.ref_tags.size).to eq 1 expect(doc.ref_tags.first.owner).to eq P("Foo#bar") expect(doc.ref_tags.first.tag_name).to eq "return" expect(doc.ref_tags.first.name).to be nil end it "parses named reference tag into ref_tags" do doc = Docstring.new("@param blah \n (see Foo#bar )") expect(doc.ref_tags.size).to eq 1 expect(doc.ref_tags.first.owner).to eq P("Foo#bar") expect(doc.ref_tags.first.tag_name).to eq "param" expect(doc.ref_tags.first.name).to eq "blah" end it "fails to parse named reference tag into ref_tags" do doc = Docstring.new("@param blah THIS_BREAKS_REFTAG (see Foo#bar)") expect(doc.ref_tags.size).to eq 0 end it "returns 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 expect(tags.size).to eq 1 expect(tags.first.text).to eq 'testing' expect(tags.first).to be_kind_of(Tags::RefTag) expect(tags.first.owner).to eq o end it "returns 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') expect(tags.size).to eq 1 expect(tags.first.text).to eq 'testing' expect(tags.first).to be_kind_of(Tags::RefTag) expect(tags.first.owner).to eq o end it "ignores invalid reference tags" do doc = Docstring.new("@param *args (see INVALID::TAG#tag)") tags = doc.tags('param') expect(tags.size).to eq 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") expect(tags.size).to eq 1 expect(tags.first.text).to eq "testing" expect(tags.first).to be_kind_of(Tags::RefTag) expect(tags.first.owner).to eq o end it "returns an empty list (and warning) if circular reftags are found" do YARD.parse_string <<-eof class Foo # @param (see #b) def a; end # @param (see #a) def b; end end eof expect(log.io.string).to match(/error.*circular reference tag in `Foo#b'/) expect(Registry.at('Foo#a').tags).to be_empty expect(Registry.at('Foo#b').tags).to be_empty end it "returns an empty list (and warning) if self-circular reftags are found" do YARD.parse_string <<-eof class Foo # @param (see #bar) def bar; end end eof expect(log.io.string).to match(/error.*circular reference tag in `Foo#bar'/) expect(Registry.at('Foo#bar').tags).to be_empty end end describe "#empty?/#blank?" do before(:all) do Tags::Library.define_tag "Invisible", :invisible_tag end it "is blank and empty if it has no content and no tags" do expect(Docstring.new).to be_blank expect(Docstring.new).to be_empty end it "isn't empty or blank if it has content" do d = Docstring.new("foo bar") expect(d).not_to be_empty expect(d).not_to be_blank end it "is empty but not blank if it has tags" do d = Docstring.new("@param foo") expect(d).to be_empty expect(d).not_to be_blank end it "is 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)") expect(d).to be_empty expect(d).not_to be_blank end it "is blank if it has no visible tags" do d = Docstring.new("@invisible_tag value") expect(d).to be_blank end it "is not 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) expect(d.blank?(false)).to be false end end describe "#delete_tags" do it "deletes tags by a given tag name" do doc = Docstring.new("@param name x\n@param name2 y\n@return foo") doc.delete_tags(:param) expect(doc.tags.size).to eq 1 end end describe "#delete_tag_if" do it "deletes 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' } expect(doc.tags.size).to eq 2 end end describe "#to_raw" do it "returns a clean representation of tags" do doc = Docstring.new("Hello world\n@return [String, X] foobar\n@param name the name\nBYE!") expect(doc.to_raw).to eq "Hello world\nBYE!\n@param [Array] name\n the name\n@return [String, X] foobar" end it "handles tags with newlines and indentation" do doc = Docstring.new("@example TITLE\n the \n example\n @foo\n@param [X] name\n the name") expect(doc.to_raw).to eq "@example TITLE\n the \n example\n @foo\n@param [X] name\n the name" end it "handles 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) expect(doc.to_raw).to eq "@example TITLE\n the \n example\n @foo" end it "handles added tags" do doc = Docstring.new("@example TITLE\n the \n example\n @foo") doc.add_tag(Tags::Tag.new('foo', 'foo')) expect(doc.to_raw).to eq "@example TITLE\n the \n example\n @foo\n@foo foo" end it "is equal to .all if not modified" do doc = Docstring.new("123\n@param") expect(doc.to_raw).to eq doc.all end # @bug gh-563 it "handles full @option tags" do doc = Docstring.new("@option foo [String] bar (nil) baz") expect(doc.to_raw).to eq "@option foo [String] bar (nil) baz" end # @bug gh-563 it "handles simple @option tags" do doc = Docstring.new("@option foo :key bar") expect(doc.to_raw).to eq "@option foo :key bar" end end describe "#dup" do it "duplicates docstring text" do doc = Docstring.new("foo") expect(doc.dup).to eq doc expect(doc.dup.all).to eq doc end it "duplicates tags to new list" do doc = Docstring.new("@param x\n@return y") doc2 = doc.dup doc2.delete_tags(:param) expect(doc.tags.size).to eq 2 expect(doc2.tags.size).to eq 1 end it "preserves summary" do doc = Docstring.new("foo. bar") expect(doc.dup.summary).to eq doc.summary end it "preserves hash_flag" do doc = Docstring.new doc.hash_flag = 'foo' expect(doc.dup.hash_flag).to eq doc.hash_flag end it "preserves line_range" do doc = Docstring.new doc.line_range = (1..2) expect(doc.dup.line_range).to eq 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') expect(object.docstring).to eq 'Docstring' expect(object.tags.map(&:tag_name)).to eq ['return'] YARD::Registry.clear end end end yard-0.9.12/spec/options_spec.rb0000755000004100000410000001114113206751010016552 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::Options do class FooOptions < YARD::Options attr_accessor :foo def initialize; self.foo = "abc" end end describe ".default_attr" do it "allows default attributes to be defined with symbols" do class DefaultOptions1 < YARD::Options default_attr :foo, 'HELLO' end o = DefaultOptions1.new o.reset_defaults expect(o.foo).to eq 'HELLO' end it "calls lambda if value is a Proc" do class DefaultOptions2 < YARD::Options default_attr :foo, lambda { 100 } end o = DefaultOptions2.new o.reset_defaults expect(o.foo).to eq 100 end end describe "#reset_defaults" do it "does not define defaults until reset is called" do class ResetDefaultOptions1 < YARD::Options default_attr :foo, 'FOO' end expect(ResetDefaultOptions1.new.foo).to be nil o = ResetDefaultOptions1.new o.reset_defaults expect(o.foo).to eq 'FOO' end it "uses 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 expect(o.foo).to eq 'FOO' end end describe "#delete" do it "deletes an option" do o = FooOptions.new o.delete(:foo) expect(o.to_hash).to eq({}) end it "does not error if an option is deleted that does not exist" do o = FooOptions.new o.delete(:foo) o.delete(:foo) expect(o.to_hash).to eq({}) end end describe "#[]" do it "handles getting option values using hash syntax" do expect(FooOptions.new[:foo]).to eq "abc" end end describe "#[]=" do it "handles setting options using hash syntax" do o = FooOptions.new o[:foo] = "xyz" expect(o[:foo]).to eq "xyz" end it "allows setting of unregistered keys" do o = FooOptions.new o[:bar] = "foo" expect(o[:bar]).to eq "foo" end end describe "#method_missing" do it "allows setting of unregistered keys" do o = FooOptions.new o.bar = 'foo' expect(o.bar).to eq 'foo' end it "allows getting values of unregistered keys (return nil)" do expect(FooOptions.new.bar).to be nil end it "prints debugging messages about unregistered keys" do expect(log).to receive(:debug).with("Attempting to access unregistered key bar on FooOptions") FooOptions.new.bar expect(log).to receive(:debug).with("Attempting to set unregistered key bar on FooOptions") FooOptions.new.bar = 1 end end describe "#update" do it "allows updating of options" do expect(FooOptions.new.update(:foo => "xyz").foo).to eq "xyz" end it "does not ignore keys with no setter (OpenStruct behaviour)" do o = FooOptions.new o.update(:bar => "xyz") expect(o.to_hash).to eq(:foo => "abc", :bar => "xyz") end end describe "#merge" do it "updates a new object" do o = FooOptions.new expect(o.merge(:foo => "xyz").object_id).not_to eq o.object_id expect(o.merge(:foo => "xyz").to_hash).to eq(:foo => "xyz") end it "adds in values from original object" do o = FooOptions.new o.update(:bar => "foo") expect(o.merge(:baz => 1).to_hash).to eq(:foo => "abc", :bar => "foo", :baz => 1) end end describe "#to_hash" do it "converts 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 expect(hash.keys).to include(:foo, :bar, :baz) expect(hash[:foo]).to eq 1 expect(hash[:bar]).to eq 2 expect(hash[:baz]).to eq "hello" end it "uses 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 expect(o.to_hash).to eq(:foo => "HELLO1") end it "ignores ivars with no accessor" do class ToHashOptions3 < YARD::Options attr_accessor :foo def initialize; @foo = 1; @bar = "NOIGNORE" end end o = ToHashOptions3.new expect(o.to_hash).to eq(:foo => 1, :bar => "NOIGNORE") end end describe "#tap" do it "supports #tap(&block) (even in 1.8.6)" do o = FooOptions.new.tap {|obj| obj.foo = :BAR } expect(o.to_hash).to eq(:foo => :BAR) end end end yard-0.9.12/spec/server/0000755000004100000410000000000013206751010015025 5ustar www-datawww-datayard-0.9.12/spec/server/adapter_spec.rb0000755000004100000410000000220113206751010020002 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe YARD::Server::Adapter do after(:all) { Server::Adapter.shutdown } describe "#add_library" do it "adds a library" do lib = LibraryVersion.new('yard') a = Adapter.new({}) expect(a.libraries).to be_empty a.add_library(lib) expect(a.libraries['yard']).to eq [lib] end end describe "#start" do it "does not implement #start" do expect { Adapter.new({}).start }.to raise_error(NotImplementedError) end end describe ".setup" do it "adds template paths and helpers" do Adapter.setup expect(Templates::Template.extra_includes).to include(DocServerHelper) expect(Templates::Engine.template_paths).to include(YARD::ROOT + '/yard/server/templates') end end describe ".shutdown" do it "cleans up template paths and helpers" do Adapter.setup Adapter.shutdown expect(Templates::Template.extra_includes).not_to include(DocServerHelper) expect(Templates::Engine.template_paths).not_to include(YARD::ROOT + '/yard/server/templates') end end end yard-0.9.12/spec/server/commands/0000755000004100000410000000000013206751010016626 5ustar www-datawww-datayard-0.9.12/spec/server/commands/library_command_spec.rb0000755000004100000410000000203413206751010023331 0ustar www-datawww-data# frozen_string_literal: true require 'ostruct' RSpec.describe YARD::Server::Commands::LibraryCommand do before do allow(Templates::Engine).to receive(:render) allow(Templates::Engine).to receive(:generate) allow(YARD).to receive(:parse) allow(Registry).to receive(:load) allow(Registry).to receive(:save) @cmd = LibraryCommand.new(:adapter => mock_adapter) @request = mock_request("/foo", :xhr? => false) @library = OpenStruct.new(:source_path => '.') @cmd.library = @library allow(@cmd).to receive(:load_yardoc).and_return(nil) end def call expect { @cmd.call(@request) }.to raise_error(NotImplementedError) end describe "#call" do it "raises NotImplementedError" do call end it "sets :rdoc as the default markup in incremental mode" do @cmd.incremental = true call expect(@cmd.options[:markup]).to eq :rdoc end it "sets :rdoc as the default markup in regular mode" do call expect(@cmd.options[:markup]).to eq :rdoc end end end yard-0.9.12/spec/server/commands/base_spec.rb0000755000004100000410000000523713206751010021111 0ustar www-datawww-data# frozen_string_literal: true class MyProcCommand < Base def initialize(&block) self.class.send(:undef_method, :run) self.class.send(:define_method, :run, &block) end end class MyCacheCommand < Base def run; cache 'foo' end end RSpec.describe YARD::Server::Commands::Base do describe "#cache" do before do @command = MyCacheCommand.new(:adapter => mock_adapter, :caching => true) @command.request = mock_request(nil) end it "does not cache if caching == false" do expect(File).not_to receive(:open) @command.caching = false @command.run end it "requires document root to cache" do expect(File).not_to receive(:open) @command.adapter.document_root = nil @command.run end it "caches to path/to/file.html and create directories" do expect(FileUtils).to receive(:mkdir_p).with('/public/path/to') expect(File).to receive(:open).with('/public/path/to/file.html', anything) @command.request.path_info = '/path/to/file.html' @command.run end end describe "#redirect" do it "returns a valid redirection" do cmd = MyProcCommand.new { redirect '/foo' } expect(cmd.call(mock_request('/foo'))).to eq( [302, {"Content-Type" => "text/html", "Location" => "/foo"}, [""]] ) end end describe "#call" do it "handles a NotFoundError and use message as body" do cmd = MyProcCommand.new { raise NotFoundError, "hello world" } s, _, b = *cmd.call(mock_request('/foo')) expect(s).to eq 404 expect(b).to eq ["hello world"] end it "does not use message as body if not provided in NotFoundError" do cmd = MyProcCommand.new { raise NotFoundError } s, _, b = *cmd.call(mock_request('/foo')) expect(s).to eq 404 expect(b).to eq ["Not found: /foo"] end it "handles 404 status code from #run" do cmd = MyProcCommand.new { self.status = 404 } s, _, b = *cmd.call(mock_request('/foo')) expect(s).to eq 404 expect(b).to eq ["Not found: /foo"] end it "does not override body if status is 404 and body is defined" do cmd = MyProcCommand.new { self.body = "foo"; self.status = 404 } s, _, b = *cmd.call(mock_request('/bar')) expect(s).to eq 404 expect(b).to eq ['foo'] end it "handles body as Array" do cmd = MyProcCommand.new { self.body = ['a', 'b', 'c'] } _, _, b = *cmd.call(mock_request('/foo')) expect(b).to eq %w(a b c) end it "allows headers to be defined" do cmd = MyProcCommand.new { headers['Foo'] = 'BAR' } _, h, = *cmd.call(mock_request('/foo')) expect(h['Foo']).to eq 'BAR' end end end yard-0.9.12/spec/server/spec_helper.rb0000755000004100000410000000121213206751010017642 0ustar www-datawww-data# frozen_string_literal: true 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 class MockRequest < OpenStruct def path; "#{script_name}#{path_info}" end end def mock_request(path_info = '/', script_name = '', extra_env = {}) opts = {:path_info => path_info, :script_name => script_name} MockRequest.new(extra_env.merge(opts)) end yard-0.9.12/spec/server/doc_server_serializer_spec.rb0000755000004100000410000000406313206751010022756 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe YARD::Server::DocServerSerializer do describe "#serialized_path" do before do Registry.clear @serializer = Server::DocServerSerializer.new end after(:all) { Server::Adapter.shutdown } it "returns '/PREFIX/library/toplevel' for root" do expect(@serializer.serialized_path(Registry.root)).to eq "toplevel" end it "returns /PREFIX/library/Object for Object in a library" do expect(@serializer.serialized_path(P('A::B::C'))).to eq 'A/B/C' end it "links to instance method as Class:method" do obj = CodeObjects::MethodObject.new(:root, :method) expect(@serializer.serialized_path(obj)).to eq 'toplevel:method' end it "links to class method as Class.method" do obj = CodeObjects::MethodObject.new(:root, :method, :class) expect(@serializer.serialized_path(obj)).to eq 'toplevel.method' end it "links to anchor for constant" do obj = CodeObjects::ConstantObject.new(:root, :FOO) expect(@serializer.serialized_path(obj)).to eq 'toplevel#FOO-constant' end it "links to anchor for class variable" do obj = CodeObjects::ClassVariableObject.new(:root, :@@foo) expect(@serializer.serialized_path(obj)).to eq 'toplevel#@@foo-classvariable' end it "links files using file/ prefix" do file = CodeObjects::ExtraFileObject.new('a/b/FooBar.md', '') expect(@serializer.serialized_path(file)).to eq 'file/FooBar' end it "escapes special characters" do obj = CodeObjects::MethodObject.new(:root, :method?) expect(@serializer.serialized_path(obj)).to eq 'toplevel:method%3F' end it "handles unicode data" do file = CodeObjects::ExtraFileObject.new("test\u0160", '') if file.name.encoding == Encoding.find("Windows-1252") expect(@serializer.serialized_path(file)).to eq 'file/test_8A' else expect(@serializer.serialized_path(file)).to eq 'file/test_C5A0' end end if defined?(::Encoding) end end yard-0.9.12/spec/server/rack_adapter_spec.rb0000755000004100000410000000135613206751010021014 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + "/spec_helper" RSpec.describe "YARD::Server::RackMiddleware" do before do begin; require 'rack'; rescue LoadError; pending "rack required for these tests" end @superapp = double(:superapp) @app = YARD::Server::RackMiddleware.new(@superapp, :libraries => {'foo' => [LibraryVersion.new('foo', nil)]}) end after(:all) { YARD::Server::Adapter.shutdown } it "handles requests" do expect(@app.call(Rack::MockRequest.env_for('/'))[0]).to eq 200 end it "passes up to the next middleware on 404" do expect(@superapp).to receive(:call).and_return([200, {}, ['OK']]) expect(@app.call(Rack::MockRequest.env_for('/INVALID'))).to eq [200, {}, ['OK']] end end yard-0.9.12/spec/server/webrick_servlet_spec.rb0000755000004100000410000000123113206751010021556 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe YARD::Server::WebrickServlet do describe "#do_GET" do it "performs a GET" do resp = OpenStruct.new class << resp def []=(name, value) (self.headers ||= {})[name] = value end end server = double(:server, :[] => nil) adapter = mock_adapter adapter.router = proc { [200, {'Header' => 'foo'}, ['body']] } WebrickServlet.new(server, adapter).do_GET(mock_request('/foo'), resp) expect(resp.status).to eq 200 expect(resp.headers).to eq('Header' => 'foo') expect(resp.body).to eq 'body' end end end yard-0.9.12/spec/server/doc_server_helper_spec.rb0000755000004100000410000000452013206751010022062 0ustar www-datawww-data# frozen_string_literal: true require 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 RSpec.describe YARD::Server::DocServerHelper do before do @helper = MockDocServerHelper.new end describe "#url_for" do it "does not link to /library/ if single_library = true" do @helper.single_library = true expect(@helper.url_for(Registry.root)).to eq "/PREFIX/toplevel" end it "returns /PREFIX/foo/version if foo has a version" do @helper.library = LibraryVersion.new('foo', 'bar') @helper.adapter.router.request.version_supplied = true expect(@helper.url_for(P('A'))).to eq '/PREFIX/foo/bar/A' end it "uses script name prefix if set" do @helper.adapter.router.request.script_name = '/mount/point' @helper.library = LibraryVersion.new('foo', 'bar') @helper.adapter.router.request.version_supplied = true expect(@helper.url_for(P('A'))).to eq '/mount/point/PREFIX/foo/bar/A' end end describe "#url_for_file" do it "properly links file objects using file/ prefix" do file = CodeObjects::ExtraFileObject.new('a/b/FooBar.md', '') expect(@helper.url_for_file(file)).to eq '/PREFIX/foo/file/a/b/FooBar.md' end it "properly links anchor portion" do file = CodeObjects::ExtraFileObject.new('a/b/FooBar.md', '') expect(@helper.url_for_file(file, 'anchor')).to eq '/PREFIX/foo/file/a/b/FooBar.md#anchor' end it "uses script name prefix if set" do @helper.adapter.router.request.script_name = '/mount/point' file = CodeObjects::ExtraFileObject.new('a/b/FooBar.md', '') expect(@helper.url_for_file(file)).to eq '/mount/point/PREFIX/foo/file/a/b/FooBar.md' end end end yard-0.9.12/spec/server/static_caching_spec.rb0000755000004100000410000000333313206751010021334 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe YARD::Server::StaticCaching do include StaticCaching describe "#check_static_cache" do def adapter; @adapter ||= mock_adapter end def request; @request ||= MockRequest.new end it "returns nil if document root is not set" do adapter.document_root = nil expect(check_static_cache).to be nil end it "reads a file from document root if path matches file on system" do request.path_info = '/hello/world.html' expect(File).to receive(:file?).with('/public/hello/world.html').and_return(true) expect(File).to receive(:open).with('/public/hello/world.html', anything).and_return('body') s, _, b = *check_static_cache expect(s).to eq 200 expect(b).to eq ["body"] end it "reads a file if path matches file on system + .html" do request.path_info = '/hello/world' expect(File).to receive(:file?).with('/public/hello/world.html').and_return(true) expect(File).to receive(:open).with('/public/hello/world.html', anything).and_return('body') s, _, b = *check_static_cache expect(s).to eq 200 expect(b).to eq ["body"] end it "returns nil if no matching file is found" do request.path_info = '/hello/foo' expect(File).to receive(:file?).with('/public/hello/foo.html').and_return(false) expect(check_static_cache).to eq nil end it "adds mount point to cache location" do request.path_info = '/hello/world.html' request.script_name = '/mount/point' expect(File).to receive(:file?).with('/public/mount/point/hello/world.html').and_return(false) expect(check_static_cache).to eq nil end end end yard-0.9.12/spec/server/router_spec.rb0000755000004100000410000000774113206751010017720 0ustar www-datawww-data# frozen_string_literal: true require 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 RSpec.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_info = '/' + args.join('/') @router = MyRouterSpecRouter.new(@adapter) @router.request = @request @router.parse_library_from_path(args.flatten) end it "parses library and version name out of path" do expect(parse('project', '1.0.0')).to eq [@projects[0], []] expect(@request.version_supplied).to be true end it "parses library and use latest version if version is not supplied" do expect(parse('project')).to eq [@projects[1], []] expect(@request.version_supplied).to be false end it "parses library and use latest version if next component is not a version" do expect(parse('project', 'notaversion')).to eq [@projects[1], ['notaversion']] expect(@request.version_supplied).to be false end it "returns nil library if no library is found" do expect(parse('notproject')).to eq [nil, ['notproject']] end it "does not parse library or version if single_library == true" do allow(@adapter).to receive(:options).and_return(:single_library => true) expect(parse('notproject')).to eq [@projects[0], ['notproject']] end end describe "#route" do def route_to(route, command, script_name = '') req = mock_request(route, script_name) router = MyRouterSpecRouter.new(@adapter) expect(command).to receive(:new) do |*args| @command = command.allocate @command.send(:initialize, *args) class << @command; define_method(:call) {|*| self } end @command end router.call(req) end it "routes /docs/OBJECT to object if single_library = true" do allow(@adapter).to receive(:options).and_return(:single_library => true) route_to('/mydocs/foo/FOO', DisplayObjectCommand) end it "routes /docs" do route_to('/mydocs/foo', LibraryIndexCommand) end it "routes /docs as index for library if single_library == true" do allow(@adapter).to receive(:options).and_return(:single_library => true) route_to('/mydocs/foo/', DisplayObjectCommand) end it "routes /docs/name/version" do route_to('/mydocs/foo/project/1.0.0', DisplayObjectCommand) expect(@command.library).to eq @projects[0] end it "routes /docs/name/ to latest version of library" do route_to('/mydocs/foo/project', DisplayObjectCommand) expect(@command.library).to eq @projects[1] end it "routes /list/name/version/class" do route_to('/mylist/foo/project/1.0.0/class', ListCommand) expect(@command.library).to eq @projects[0] end it "routes /list/name/version/methods" do route_to('/mylist/foo/project/1.0.0/methods', ListCommand) expect(@command.library).to eq @projects[0] end it "routes /list/name/version/files" do route_to('/mylist/foo/project/1.0.0/files', ListCommand) expect(@command.library).to eq @projects[0] end it "routes /list/name to latest version of library" do route_to('/mylist/foo/project/class', ListCommand) expect(@command.library).to eq @projects[1] end it "routes /search/name/version" do route_to('/mysearch/foo/project/1.0.0', SearchCommand) expect(@command.library).to eq @projects[0] end it "routes /search/name to latest version of library" do route_to('/mysearch/foo/project', SearchCommand) expect(@command.library).to eq @projects[1] end it "searches static files for non-existent library" do route_to('/mydocs/foo/notproject', RootRequestCommand) end end end yard-0.9.12/spec/spec_helper.rb0000755000004100000410000001673513206751010016354 0ustar www-datawww-data# frozen_string_literal: true require "rubygems" begin require "rspec" rescue LoadError require "spec" end begin require 'bundler/setup' rescue LoadError nil # noop end require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'yard')) unless defined?(HAVE_RIPPER) begin require 'ripper'; rescue LoadError; nil end HAVE_RIPPER = defined?(::Ripper) && !ENV['LEGACY'] ? true : false LEGACY_PARSER = !HAVE_RIPPER class YARD::Parser::SourceParser def self.parser_type; @parser_type == :ruby ? :ruby18 : @parser_type end end if ENV['LEGACY'] end begin require 'coveralls' Coveralls.wear! end if ENV['CI'] && HAVE_RIPPER NAMED_OPTIONAL_ARGUMENTS = RUBY_VERSION >= '2.1.0' 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('::', '/') $LOADED_FEATURES.find_all {|p| p.include? underscore }.each do |found_fname| next unless File.exist? found_fname YARD::Parser::SourceParser.new.parse(found_fname) 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('::', '/') $LOADED_FEATURES.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} }") expect(hash.keys.first).to eq 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 } # isolate environment of each test # any other global settings which might be modified by a test should also # be saved and restored here config.around(:each) do |example| saved_level = log.level example.run log.level = saved_level end # rspec-expectations config goes here. You can use an alternate # assertion/expectation library such as wrong or the stdlib/minitest # assertions if you prefer. config.expect_with :rspec do |expectations| # This option will default to `true` in RSpec 4. It makes the `description` # and `failure_message` of custom matchers include text for helper methods # defined using `chain`, e.g.: # be_bigger_than(2).and_smaller_than(4).description # # => "be bigger than 2 and smaller than 4" # ...rather than: # # => "be bigger than 2" expectations.include_chain_clauses_in_custom_matcher_descriptions = true end # rspec-mocks config goes here. You can use an alternate test double # library (such as bogus or mocha) by changing the `mock_with` option here. config.mock_with :rspec do |mocks| # Prevents you from mocking or stubbing a method that does not exist on # a real object. This is generally recommended, and will default to # `true` in RSpec 4. # mocks.verify_partial_doubles = true # FIXME: Not yet working end # This option will default to `:apply_to_host_groups` in RSpec 4 (and will # have no way to turn it off -- the option exists only for backwards # compatibility in RSpec 3). It causes shared context metadata to be # inherited by the metadata hash of host groups and examples, rather than # triggering implicit auto-inclusion in groups with matching metadata. config.shared_context_metadata_behavior = :apply_to_host_groups # This allows you to limit a spec run to individual examples or groups # you care about by tagging them with `:focus` metadata. When nothing # is tagged with `:focus`, all examples get run. RSpec also provides # aliases for `it`, `describe`, and `context` that include `:focus` # metadata: `fit`, `fdescribe` and `fcontext`, respectively. config.filter_run_when_matching :focus # Allows RSpec to persist some state between runs in order to support # the `--only-failures` and `--next-failure` CLI options. We recommend # you configure your source control system to ignore this file. config.example_status_persistence_file_path = "spec/examples.txt" # Limits the available syntax to the non-monkey patched syntax that is # recommended. For more details, see: # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode config.disable_monkey_patching! # This setting enables warnings. It's recommended, but in some cases may # be too noisy due to issues in dependencies. config.warnings = false # Many RSpec users commonly either run the entire suite or an individual # file, and it's useful to allow more verbose output when running an # individual spec file. if config.files_to_run.one? # Use the documentation formatter for detailed output, # unless a formatter has already been configured # (e.g. via a command-line flag). config.default_formatter = 'doc' end # Print the N slowest examples and example groups at the # end of the spec run, to help surface which specs are running # particularly slow. config.profile_examples = 5 # Run specs in random order to surface order dependencies. If you find an # order dependency and want to debug it, you can fix the order by providing # the seed, which is printed after each run. # --seed 1234 # config.order = :random # FIXME: Not yet working # Seed global randomization in this process using the `--seed` CLI option. # Setting this allows you to use `--seed` to deterministically reproduce # test failures related to randomization by passing the same `--seed` value # as the one that triggered the failure. Kernel.srand config.seed end include YARD yard-0.9.12/spec/parser/0000755000004100000410000000000013206751010015013 5ustar www-datawww-datayard-0.9.12/spec/parser/examples/0000755000004100000410000000000013206751010016631 5ustar www-datawww-datayard-0.9.12/spec/parser/examples/multifile.c.txt0000755000004100000410000000057013206751010021612 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.9.12/spec/parser/examples/extrafile.c.txt0000755000004100000410000000010513206751010021575 0ustar www-datawww-data/* * foo */ VALUE rb_extra(VALUE obj, VALUE n) { return Qtrue; } yard-0.9.12/spec/parser/examples/example1.rb.txt0000755000004100000410000000011713206751010021512 0ustar www-datawww-datamodule Hello class Hi # Docstring def me "Value" end end endyard-0.9.12/spec/parser/examples/parse_in_order_001.rb.txt0000755000004100000410000000003413206751010023347 0ustar www-datawww-dataclass MyModule::MyClass end yard-0.9.12/spec/parser/examples/tag_handler_001.rb.txt0000755000004100000410000000007713206751010022633 0ustar www-datawww-dataclass Foo # @api public # @return nil def foo end endyard-0.9.12/spec/parser/examples/array.c.txt0000755000004100000410000047335513206751010020755 0ustar www-datawww-data/********************************************************************** array.c - $Author$ 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 "internal.h" #include "ruby/util.h" #include "ruby/st.h" #include "probes.h" #include "id.h" #include "debug_counter.h" #ifndef ARRAY_DEBUG # define NDEBUG #endif #include "ruby_assert.h" VALUE rb_cArray; static ID id_div; /* for OPTIMIZED_CMP: */ #define id_cmp idCmp #define ARY_DEFAULT_SIZE 16 #define ARY_MAX_SIZE (LONG_MAX / (int)sizeof(VALUE)) # define ARY_SHARED_P(ary) \ (assert(!FL_TEST((ary), ELTS_SHARED) || !FL_TEST((ary), RARRAY_EMBED_FLAG)), \ FL_TEST((ary),ELTS_SHARED)!=0) # define ARY_EMBED_P(ary) \ (assert(!FL_TEST((ary), ELTS_SHARED) || !FL_TEST((ary), RARRAY_EMBED_FLAG)), \ FL_TEST((ary), RARRAY_EMBED_FLAG)!=0) #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_HEAP_SIZE(a) (assert(!ARY_EMBED_P(a)), assert(ARY_OWNS_HEAP_P(a)), RARRAY(a)->as.heap.aux.capa * sizeof(VALUE)) #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)); \ 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 { \ const VALUE _ary_ = (ary); \ const VALUE _value_ = (value); \ assert(!ARY_EMBED_P(_ary_)); \ assert(ARY_SHARED_P(_ary_)); \ assert(ARY_SHARED_ROOT_P(_value_)); \ RB_OBJ_WRITE(_ary_, &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_SHARED_OCCUPIED(ary) (ARY_SHARED_NUM(ary) == 1) #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) #define ARY_SET(a, i, v) RARRAY_ASET((assert(!ARY_SHARED_P(a)), (a)), (i), (v)) void rb_mem_clear(register VALUE *mem, register long size) { while (size--) { *mem++ = Qnil; } } static void ary_mem_clear(VALUE ary, long beg, long size) { RARRAY_PTR_USE(ary, ptr, { rb_mem_clear(ptr + beg, size); }); } static inline void memfill(register VALUE *mem, register long size, register VALUE val) { while (size--) { *mem++ = val; } } static void ary_memfill(VALUE ary, long beg, long size, VALUE val) { RARRAY_PTR_USE(ary, ptr, { memfill(ptr + beg, size, val); RB_OBJ_WRITTEN(ary, Qundef, val); }); } static void ary_memcpy0(VALUE ary, long beg, long argc, const VALUE *argv, VALUE buff_owner_ary) { #if 1 assert(!ARY_SHARED_P(buff_owner_ary)); if (argc > (int)(128/sizeof(VALUE)) /* is magic number (cache line size) */) { rb_gc_writebarrier_remember(buff_owner_ary); RARRAY_PTR_USE(ary, ptr, { MEMCPY(ptr+beg, argv, VALUE, argc); }); } else { int i; RARRAY_PTR_USE(ary, ptr, { for (i=0; i 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 { SIZED_REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, capacity, RARRAY(ary)->as.heap.aux.capa); } ARY_SET_CAPA(ary, (capacity)); } else { if (!ARY_EMBED_P(ary)) { long len = RARRAY_LEN(ary); const VALUE *ptr = RARRAY_CONST_PTR(ary); if (len > capacity) len = capacity; MEMCPY((VALUE *)RARRAY(ary)->as.ary, ptr, VALUE, len); FL_SET_EMBED(ary); ARY_SET_LEN(ary, len); ruby_xfree((VALUE *)ptr); } } } static inline void ary_shrink_capa(VALUE ary) { long capacity = ARY_HEAP_LEN(ary); long old_capa = RARRAY(ary)->as.heap.aux.capa; assert(!ARY_SHARED_P(ary)); assert(old_capa >= capacity); if (old_capa > capacity) REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, capacity); } static void ary_double_capa(VALUE ary, long min) { long new_capa = ARY_CAPA(ary) / 2; if (new_capa < ARY_DEFAULT_SIZE) { new_capa = ARY_DEFAULT_SIZE; } if (new_capa >= ARY_MAX_SIZE - min) { new_capa = (ARY_MAX_SIZE - min) / 2; } new_capa += min; ary_resize_capa(ary, new_capa); } static void rb_ary_decrement_share(VALUE shared) { if (shared) { long 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) { long 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) { rb_check_frozen(ary); } void rb_ary_modify(VALUE ary) { rb_ary_modify_check(ary); if (ARY_SHARED_P(ary)) { long shared_len, len = RARRAY_LEN(ary); VALUE shared = ARY_SHARED(ary); if (len <= RARRAY_EMBED_LEN_MAX) { const VALUE *ptr = ARY_HEAP_PTR(ary); FL_UNSET_SHARED(ary); FL_SET_EMBED(ary); MEMCPY((VALUE *)ARY_EMBED_PTR(ary), ptr, VALUE, len); rb_ary_decrement_share(shared); ARY_SET_EMBED_LEN(ary, len); } else if (ARY_SHARED_OCCUPIED(shared) && len > ((shared_len = RARRAY_LEN(shared))>>1)) { long shift = RARRAY_CONST_PTR(ary) - RARRAY_CONST_PTR(shared); FL_UNSET_SHARED(ary); ARY_SET_PTR(ary, RARRAY_CONST_PTR(shared)); ARY_SET_CAPA(ary, shared_len); RARRAY_PTR_USE(ary, ptr, { MEMMOVE(ptr, ptr+shift, VALUE, len); }); FL_SET_EMBED(shared); rb_ary_decrement_share(shared); } else { VALUE *ptr = ALLOC_N(VALUE, len); MEMCPY(ptr, RARRAY_CONST_PTR(ary), VALUE, len); rb_ary_unshare(ary); ARY_SET_CAPA(ary, len); ARY_SET_PTR(ary, ptr); } rb_gc_writebarrier_remember(ary); } } static VALUE ary_ensure_room_for_push(VALUE ary, long add_len) { long old_len = RARRAY_LEN(ary); long new_len = old_len + add_len; long capa; if (old_len > ARY_MAX_SIZE - add_len) { rb_raise(rb_eIndexError, "index %ld too big", new_len); } if (ARY_SHARED_P(ary)) { if (new_len > RARRAY_EMBED_LEN_MAX) { VALUE shared = ARY_SHARED(ary); if (ARY_SHARED_OCCUPIED(shared)) { if (RARRAY_CONST_PTR(ary) - RARRAY_CONST_PTR(shared) + new_len <= RARRAY_LEN(shared)) { rb_ary_modify_check(ary); return shared; } else { /* if array is shared, then it is likely it participate in push/shift pattern */ rb_ary_modify(ary); capa = ARY_CAPA(ary); if (new_len > capa - (capa >> 6)) { ary_double_capa(ary, new_len); } return ary; } } } rb_ary_modify(ary); } else { rb_ary_modify_check(ary); } capa = ARY_CAPA(ary); if (new_len > capa) { ary_double_capa(ary, new_len); } return ary; } /* * call-seq: * ary.freeze -> ary * * Calls Object#freeze on +ary+ to prevent any further * modification. A RuntimeError will be raised if a modification * attempt is made. * */ VALUE rb_ary_freeze(VALUE ary) { return rb_obj_freeze(ary); } /* * call-seq: * ary.frozen? -> true or false * * Return +true+ if this array is frozen (or temporarily frozen * while being sorted). See also Object#frozen? */ static VALUE rb_ary_frozen_p(VALUE ary) { if (OBJ_FROZEN(ary)) return Qtrue; return Qfalse; } /* This can be used to take a snapshot of an array (with e.g. rb_ary_replace) and check later whether the array has been modified from the snapshot. The snapshot is cheap, though if something does modify the array it will pay the cost of copying it. If Array#pop or Array#shift has been called, the array will be still shared with the snapshot, but the array length will differ. */ VALUE rb_ary_shared_with_p(VALUE ary1, VALUE ary2) { if (!ARY_EMBED_P(ary1) && ARY_SHARED_P(ary1) && !ARY_EMBED_P(ary2) && ARY_SHARED_P(ary2) && RARRAY(ary1)->as.heap.aux.shared == RARRAY(ary2)->as.heap.aux.shared && RARRAY(ary1)->as.heap.len == RARRAY(ary2)->as.heap.len) { return Qtrue; } return Qfalse; } static VALUE ary_alloc(VALUE klass) { NEWOBJ_OF(ary, struct RArray, klass, T_ARRAY | RARRAY_EMBED_FLAG | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0)); /* Created array is: * FL_SET_EMBED((VALUE)ary); * ARY_SET_EMBED_LEN((VALUE)ary, 0); */ return (VALUE)ary; } static VALUE empty_ary_alloc(VALUE klass) { RUBY_DTRACE_CREATE_HOOK(ARRAY, 0); return ary_alloc(klass); } static VALUE ary_new(VALUE klass, long capa) { VALUE ary,*ptr; if (capa < 0) { rb_raise(rb_eArgError, "negative array size (or size too big)"); } if (capa > ARY_MAX_SIZE) { rb_raise(rb_eArgError, "array size too big"); } RUBY_DTRACE_CREATE_HOOK(ARRAY, capa); ary = ary_alloc(klass); if (capa > RARRAY_EMBED_LEN_MAX) { ptr = ALLOC_N(VALUE, capa); FL_UNSET_EMBED(ary); ARY_SET_PTR(ary, ptr); ARY_SET_CAPA(ary, capa); ARY_SET_HEAP_LEN(ary, 0); } return ary; } VALUE rb_ary_new_capa(long capa) { return ary_new(rb_cArray, capa); } VALUE rb_ary_new(void) { return rb_ary_new2(RARRAY_EMBED_LEN_MAX); } VALUE (rb_ary_new_from_args)(long n, ...) { va_list ar; VALUE ary; long i; ary = rb_ary_new2(n); va_start(ar, n); for (i=0; i 0 && elts) { ary_memcpy(ary, 0, n, elts); ARY_SET_LEN(ary, n); } return ary; } VALUE rb_ary_new_from_values(long n, const VALUE *elts) { return rb_ary_tmp_new_from_values(rb_cArray, n, elts); } VALUE rb_ary_tmp_new(long capa) { return ary_new(0, capa); } VALUE rb_ary_tmp_new_fill(long capa) { VALUE ary = ary_new(0, capa); ary_memfill(ary, 0, capa, Qnil); ARY_SET_LEN(ary, capa); return ary; } void rb_ary_free(VALUE ary) { if (ARY_OWNS_HEAP_P(ary)) { RB_DEBUG_COUNTER_INC(obj_ary_ptr); ruby_sized_xfree((void *)ARY_HEAP_PTR(ary), ARY_HEAP_SIZE(ary)); } else { RB_DEBUG_COUNTER_INC(obj_ary_embed); } } RUBY_FUNC_EXPORTED size_t rb_ary_memsize(VALUE ary) { if (ARY_OWNS_HEAP_P(ary)) { return ARY_CAPA(ary) * sizeof(VALUE); } else { return 0; } } static inline void ary_discard(VALUE ary) { rb_ary_free(ary); RBASIC(ary)->flags |= RARRAY_EMBED_FLAG; RBASIC(ary)->flags &= ~RARRAY_EMBED_LEN_MASK; } static VALUE ary_make_shared(VALUE ary) { assert(!ARY_EMBED_P(ary)); if (ARY_SHARED_P(ary)) { return ARY_SHARED(ary); } else if (ARY_SHARED_ROOT_P(ary)) { return ary; } else if (OBJ_FROZEN(ary)) { ary_shrink_capa(ary); FL_SET_SHARED_ROOT(ary); ARY_SET_SHARED_NUM(ary, 1); return ary; } else { long capa = ARY_CAPA(ary), len = RARRAY_LEN(ary); NEWOBJ_OF(shared, struct RArray, 0, T_ARRAY | (RGENGC_WB_PROTECTED_ARRAY ? FL_WB_PROTECTED : 0)); FL_UNSET_EMBED(shared); ARY_SET_LEN((VALUE)shared, capa); ARY_SET_PTR((VALUE)shared, RARRAY_CONST_PTR(ary)); ary_mem_clear((VALUE)shared, len, capa - len); 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) { long len = RARRAY_LEN(ary); if (len <= RARRAY_EMBED_LEN_MAX) { VALUE subst = rb_ary_new2(len); ary_memcpy(subst, 0, len, RARRAY_CONST_PTR(ary)); ARY_SET_EMBED_LEN(subst, len); 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_with_id(ary, T_ARRAY, "Array", idTo_ary); } VALUE rb_check_array_type(VALUE ary) { return rb_check_convert_type_with_id(ary, T_ARRAY, "Array", idTo_ary); } /* * call-seq: * Array.try_convert(obj) -> array or nil * * Tries to convert +obj+ into an array, using +to_ary+ method. Returns the * converted array or +nil+ if +obj+ cannot be converted for any reason. * This method can be used 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, default=nil) * Array.new(array) * Array.new(size) {|index| block } * * Returns a new array. * * In the first form, if no arguments are sent, the new array will be empty. * When a +size+ and an optional +default+ are sent, an array is created with * +size+ copies of +default+. Take notice that all elements will reference the * same object +default+. * * The second form creates a copy of the array passed as a parameter (the * array is generated by calling to_ary on the parameter). * * first_array = ["Matz", "Guido"] * * second_array = Array.new(first_array) #=> ["Matz", "Guido"] * * first_array.equal? second_array #=> false * * In the last form, an array of the given size is created. Each element in * this array is created by passing the element's index to the given block * and storing the return value. * * Array.new(3){ |index| index ** 2 } * # => [0, 1, 4] * * == Common gotchas * * When sending the second parameter, the same object will be used as the * value for all the array elements: * * a = Array.new(2, Hash.new) * # => [{}, {}] * * a[0]['cat'] = 'feline' * a # => [{"cat"=>"feline"}, {"cat"=>"feline"}] * * a[1]['cat'] = 'Felix' * a # => [{"cat"=>"Felix"}, {"cat"=>"Felix"}] * * Since all the Array elements store the same hash, changes to one of them * will affect them all. * * If multiple copies are what you want, you should use the block * version which uses the result of that block each time an element * of the array needs to be initialized: * * a = Array.new(2) { Hash.new } * a[0]['cat'] = 'feline' * a # => [{"cat"=>"feline"}, {}] * */ 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_CONST_PTR(ary) != 0) { ruby_sized_xfree((void *)RARRAY_CONST_PTR(ary), ARY_HEAP_SIZE(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); /* NUM2LONG() may call size.to_int, ary can be frozen, modified, etc */ if (len < 0) { rb_raise(rb_eArgError, "negative array size"); } if (len > ARY_MAX_SIZE) { rb_raise(rb_eArgError, "array size too big"); } /* recheck after argument conversion */ 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 [1, "a", /^A/] * Array[ 1, 'a', /^A/ ] # => [1, "a", /^A/] * [ 1, 'a', /^A/ ] # => [1, "a", /^A/] */ static VALUE rb_ary_s_create(int argc, VALUE *argv, VALUE klass) { VALUE ary = ary_new(klass, argc); if (argc > 0 && argv) { ary_memcpy(ary, 0, argc, argv); ARY_SET_LEN(ary, argc); } return ary; } void rb_ary_store(VALUE ary, long idx, VALUE val) { long len = RARRAY_LEN(ary); if (idx < 0) { idx += len; if (idx < 0) { rb_raise(rb_eIndexError, "index %ld too small for array; minimum: %ld", idx - len, -len); } } else if (idx >= ARY_MAX_SIZE) { rb_raise(rb_eIndexError, "index %ld too big", idx); } rb_ary_modify(ary); if (idx >= ARY_CAPA(ary)) { ary_double_capa(ary, idx); } if (idx > len) { ary_mem_clear(ary, len, idx - len + 1); } if (idx >= len) { ARY_SET_LEN(ary, idx + 1); } ARY_SET(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); ary_memcpy(result, 0, len, RARRAY_CONST_PTR(ary) + offset); 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_CONST_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, const VALUE *argv, VALUE ary, enum ary_take_pos_flags last) { VALUE nv; long n; long len; long offset = 0; rb_scan_args(argc, argv, "1", &nv); n = NUM2LONG(nv); len = RARRAY_LEN(ary); if (n > len) { n = len; } else if (n < 0) { rb_raise(rb_eArgError, "negative array size"); } if (last) { offset = len - n; } return ary_make_partial(ary, rb_cArray, offset, n); } /* * call-seq: * ary << obj -> ary * * 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. * * a = [ 1, 2 ] * a << "c" << "d" << [ 3, 4 ] * #=> [ 1, 2, "c", "d", [ 3, 4 ] ] * a * #=> [ 1, 2, "c", "d", [ 3, 4 ] ] * */ VALUE rb_ary_push(VALUE ary, VALUE item) { long idx = RARRAY_LEN(ary); VALUE target_ary = ary_ensure_room_for_push(ary, 1); RARRAY_PTR_USE(ary, ptr, { RB_OBJ_WRITE(target_ary, &ptr[idx], item); }); ARY_SET_LEN(ary, idx + 1); return ary; } VALUE rb_ary_cat(VALUE ary, const VALUE *argv, long len) { long oldlen = RARRAY_LEN(ary); VALUE target_ary = ary_ensure_room_for_push(ary, len); ary_memcpy0(ary, oldlen, len, argv, target_ary); ARY_SET_LEN(ary, oldlen + len); return ary; } /* * call-seq: * ary.push(obj, ... ) -> ary * * 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. See also Array#pop for the opposite * effect. * * a = [ "a", "b", "c" ] * a.push("d", "e", "f") * #=> ["a", "b", "c", "d", "e", "f"] * [1, 2, 3].push(4).push(5) * #=> [1, 2, 3, 4, 5] */ static VALUE rb_ary_push_m(int argc, VALUE *argv, VALUE ary) { return rb_ary_cat(ary, argv, argc); } VALUE rb_ary_pop(VALUE ary) { long n; rb_ary_modify_check(ary); n = RARRAY_LEN(ary); if (n == 0) return Qnil; if (ARY_OWNS_HEAP_P(ary) && n * 3 < ARY_CAPA(ary) && ARY_CAPA(ary) > ARY_DEFAULT_SIZE) { ary_resize_capa(ary, n * 2); } --n; ARY_SET_LEN(ary, n); return RARRAY_AREF(ary, n); } /* * call-seq: * ary.pop -> obj or nil * ary.pop(n) -> new_ary * * 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. See also * Array#push for the opposite effect. * * 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; long len = RARRAY_LEN(ary); rb_ary_modify_check(ary); if (len == 0) return Qnil; top = RARRAY_AREF(ary, 0); if (!ARY_SHARED_P(ary)) { if (len < ARY_DEFAULT_SIZE) { RARRAY_PTR_USE(ary, ptr, { MEMMOVE(ptr, ptr+1, VALUE, len-1); }); /* WB: no new reference */ ARY_INCREASE_LEN(ary, -1); return top; } assert(!ARY_EMBED_P(ary)); /* ARY_EMBED_LEN_MAX < ARY_DEFAULT_SIZE */ ARY_SET(ary, 0, Qnil); ary_make_shared(ary); } else if (ARY_SHARED_OCCUPIED(ARY_SHARED(ary))) { RARRAY_PTR_USE(ary, ptr, ptr[0] = Qnil); } ARY_INCREASE_PTR(ary, 1); /* shift ptr */ ARY_INCREASE_LEN(ary, -1); return top; } /* * call-seq: * ary.shift -> obj or nil * ary.shift(n) -> new_ary * * Removes the first element of +self+ and returns 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. With +ary+ * containing only the remainder elements, not including what was shifted to * +new_ary+. See also Array#unshift for the opposite effect. * * 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)) { if (ARY_SHARED_OCCUPIED(ARY_SHARED(ary))) { setup_occupied_shared: ary_mem_clear(ary, 0, n); } ARY_INCREASE_PTR(ary, n); } else { if (RARRAY_LEN(ary) < ARY_DEFAULT_SIZE) { RARRAY_PTR_USE(ary, ptr, { MEMMOVE(ptr, ptr+n, VALUE, RARRAY_LEN(ary)-n); }); /* WB: no new reference */ } else { ary_make_shared(ary); goto setup_occupied_shared; } } ARY_INCREASE_LEN(ary, -n); return result; } static VALUE ary_ensure_room_for_unshift(VALUE ary, int argc) { long len = RARRAY_LEN(ary); long new_len = len + argc; long capa; const VALUE *head, *sharedp; if (len > ARY_MAX_SIZE - argc) { rb_raise(rb_eIndexError, "index %ld too big", new_len); } if (ARY_SHARED_P(ary)) { VALUE shared = ARY_SHARED(ary); capa = RARRAY_LEN(shared); if (ARY_SHARED_OCCUPIED(shared) && capa > new_len) { head = RARRAY_CONST_PTR(ary); sharedp = RARRAY_CONST_PTR(shared); goto makeroom_if_need; } } rb_ary_modify(ary); capa = ARY_CAPA(ary); if (capa - (capa >> 6) <= new_len) { ary_double_capa(ary, new_len); } /* use shared array for big "queues" */ if (new_len > ARY_DEFAULT_SIZE * 4) { /* make a room for unshifted items */ capa = ARY_CAPA(ary); ary_make_shared(ary); head = sharedp = RARRAY_CONST_PTR(ary); goto makeroom; makeroom_if_need: if (head - sharedp < argc) { long room; makeroom: room = capa - new_len; room -= room >> 4; MEMMOVE((VALUE *)sharedp + argc + room, head, VALUE, len); head = sharedp + argc + room; } ARY_SET_PTR(ary, head - argc); assert(ARY_SHARED_OCCUPIED(ARY_SHARED(ary))); return ARY_SHARED(ary); } else { /* sliding items */ RARRAY_PTR_USE(ary, ptr, { MEMMOVE(ptr + argc, ptr, VALUE, len); }); return ary; } } /* * call-seq: * ary.unshift(obj, ...) -> ary * * Prepends objects to the front of +self+, moving other elements upwards. * See also Array#shift for the opposite effect. * * 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 = RARRAY_LEN(ary); VALUE target_ary; if (argc == 0) { rb_ary_modify_check(ary); return ary; } target_ary = ary_ensure_room_for_unshift(ary, argc); ary_memcpy0(ary, 0, argc, argv, target_ary); ARY_SET_LEN(ary, len + 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) { long len = RARRAY_LEN(ary); if (len == 0) return Qnil; if (offset < 0 || len <= offset) { return Qnil; } return RARRAY_AREF(ary, offset); } VALUE rb_ary_entry(VALUE ary, long offset) { long len = RARRAY_LEN(ary); const VALUE *ptr = RARRAY_CONST_PTR(ary); if (len == 0) return Qnil; if (offset < 0) { offset += len; if (offset < 0) return Qnil; } else if (len <= offset) { return Qnil; } return ptr[offset]; } VALUE rb_ary_subseq(VALUE ary, long beg, long len) { VALUE klass; long alen = RARRAY_LEN(ary); if (beg > alen) return Qnil; if (beg < 0 || len < 0) return Qnil; if (alen < len || alen < beg + len) { len = alen - beg; } klass = rb_obj_class(ary); if (len == 0) return ary_new(klass, 0); return ary_make_partial(ary, klass, beg, len); } /* * call-seq: * ary[index] -> obj or nil * ary[start, length] -> new_ary or nil * ary[range] -> new_ary or nil * ary.slice(index) -> obj or nil * ary.slice(start, length) -> new_ary or nil * ary.slice(range) -> new_ary or nil * * Element Reference --- Returns the element at +index+, or returns a * subarray starting at the +start+ index and continuing for +length+ * elements, or returns a subarray specified by +range+ of indices. * * Negative indices count backward from the end of the array (-1 is the last * element). For +start+ and +range+ cases the starting index is just before * an element. Additionally, an empty array is returned when the starting * index for an element range is at the end of the array. * * 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[6, 1] #=> nil * a[5, 1] #=> [] * a[5..10] #=> [] * */ VALUE rb_ary_aref(int argc, const 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", NULL, NULL); } 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: * ary.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" */ VALUE rb_ary_at(VALUE ary, VALUE pos) { return rb_ary_entry(ary, NUM2LONG(pos)); } /* * call-seq: * ary.first -> obj or nil * ary.first(n) -> new_ary * * 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. See also Array#last for * the opposite effect. * * 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_AREF(ary, 0); } else { return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_FIRST); } } /* * call-seq: * ary.last -> obj or nil * ary.last(n) -> new_ary * * Returns the last element(s) of +self+. If the array is empty, * the first form returns +nil+. * * See also Array#first for the opposite effect. * * a = [ "w", "x", "y", "z" ] * a.last #=> "z" * a.last(2) #=> ["y", "z"] */ VALUE rb_ary_last(int argc, const VALUE *argv, VALUE ary) { if (argc == 0) { long len = RARRAY_LEN(ary); if (len == 0) return Qnil; return RARRAY_AREF(ary, len-1); } else { return ary_take_first_or_last(argc, argv, ary, ARY_TAKE_LAST); } } /* * call-seq: * ary.fetch(index) -> obj * ary.fetch(index, default) -> obj * ary.fetch(index) { |index| block } -> obj * * Tries to return the element at position +index+, but throws an IndexError * exception if the referenced +index+ lies outside of the array bounds. This * error can be prevented by supplying a second argument, which will act as a * +default+ value. * * Alternatively, if a block is given it will only be executed when an * invalid +index+ is referenced. * * 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(100) { |i| puts "#{i} is out of bounds" } * #=> "100 is out of bounds" */ 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 outside of array bounds: %ld...%ld", idx - (idx < 0 ? RARRAY_LEN(ary) : 0), -RARRAY_LEN(ary), RARRAY_LEN(ary)); } return ifnone; } return RARRAY_AREF(ary, idx); } /* * call-seq: * ary.find_index(obj) -> int or nil * ary.find_index { |item| block } -> int or nil * ary.find_index -> Enumerator * ary.index(obj) -> int or nil * ary.index { |item| block } -> int or nil * ary.index -> Enumerator * * Returns the _index_ of the first object in +ary+ such that the object is * == to +obj+. * * If a block is given instead of an argument, returns the _index_ of the * first object for which the block returns +true+. Returns +nil+ if no * match is found. * * See also Array#rindex. * * An Enumerator is returned if neither a block nor argument is given. * * a = [ "a", "b", "c" ] * a.index("b") #=> 1 * a.index("z") #=> nil * a.index { |x| x == "b" } #=> 1 */ 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 * ary.rindex { |item| block } -> int or nil * ary.rindex -> Enumerator * * Returns the _index_ of the last object in +self+ == to +obj+. * * If a block is given instead of an argument, returns the _index_ of the * first object for which the block returns +true+, starting from the last * object. * * Returns +nil+ if no match is found. * * See also Array#index. * * If neither block nor argument is given, an Enumerator is returned instead. * * 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), len; if (argc == 0) { RETURN_ENUMERATOR(ary, 0, 0); while (i--) { if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) return LONG2NUM(i); if (i > (len = RARRAY_LEN(ary))) { i = len; } } return Qnil; } rb_check_arity(argc, 0, 1); val = argv[0]; if (rb_block_given_p()) rb_warn("given block not used"); while (i--) { VALUE e = RARRAY_AREF(ary, i); if (rb_equal(e, val)) { return LONG2NUM(i); } } return Qnil; } VALUE rb_ary_to_ary(VALUE obj) { VALUE tmp = rb_check_array_type(obj); if (!NIL_P(tmp)) return tmp; return rb_ary_new3(1, obj); } static void rb_ary_splice(VALUE ary, long beg, long len, const VALUE *rptr, long rlen) { long olen; long rofs; if (len < 0) rb_raise(rb_eIndexError, "negative length (%ld)", len); olen = RARRAY_LEN(ary); if (beg < 0) { beg += olen; if (beg < 0) { rb_raise(rb_eIndexError, "index %ld too small for array; minimum: %ld", beg - olen, -olen); } } if (olen < len || olen < beg + len) { len = olen - beg; } { const VALUE *optr = RARRAY_CONST_PTR(ary); rofs = (rptr >= optr && rptr < optr + olen) ? rptr - optr : -1; } if (beg >= olen) { VALUE target_ary; if (beg > ARY_MAX_SIZE - rlen) { rb_raise(rb_eIndexError, "index %ld too big", beg); } target_ary = ary_ensure_room_for_push(ary, rlen-len); /* len is 0 or negative */ len = beg + rlen; ary_mem_clear(ary, olen, beg - olen); if (rlen > 0) { if (rofs != -1) rptr = RARRAY_CONST_PTR(ary) + rofs; ary_memcpy0(ary, beg, rlen, rptr, target_ary); } ARY_SET_LEN(ary, len); } else { long alen; if (olen - len > ARY_MAX_SIZE - rlen) { rb_raise(rb_eIndexError, "index %ld too big", olen + rlen - len); } rb_ary_modify(ary); alen = olen + rlen - len; if (alen >= ARY_CAPA(ary)) { ary_double_capa(ary, alen); } if (len != rlen) { RARRAY_PTR_USE(ary, ptr, MEMMOVE(ptr + beg + rlen, ptr + beg + len, VALUE, olen - (beg + len))); ARY_SET_LEN(ary, alen); } if (rlen > 0) { if (rofs != -1) rptr = RARRAY_CONST_PTR(ary) + rofs; MEMMOVE(RARRAY_PTR(ary) + beg, rptr, VALUE, rlen); } } } void rb_ary_set_len(VALUE ary, long len) { long capa; rb_ary_modify_check(ary); if (ARY_SHARED_P(ary)) { rb_raise(rb_eRuntimeError, "can't set length of shared "); } if (len > (capa = (long)ARY_CAPA(ary))) { rb_bug("probable buffer overflow: %ld for %ld", len, capa); } ARY_SET_LEN(ary, len); } /*! * expands or shrinks \a ary to \a len elements. * expanded region will be filled with Qnil. * \param ary an array * \param len new size * \return \a ary * \post the size of \a ary is \a len. */ VALUE rb_ary_resize(VALUE ary, long len) { long olen; rb_ary_modify(ary); olen = RARRAY_LEN(ary); if (len == olen) return ary; if (len > ARY_MAX_SIZE) { rb_raise(rb_eIndexError, "index %ld too big", len); } if (len > olen) { if (len >= ARY_CAPA(ary)) { ary_double_capa(ary, len); } ary_mem_clear(ary, olen, len - olen); ARY_SET_LEN(ary, len); } else if (ARY_EMBED_P(ary)) { ARY_SET_EMBED_LEN(ary, len); } else if (len <= RARRAY_EMBED_LEN_MAX) { VALUE tmp[RARRAY_EMBED_LEN_MAX]; MEMCPY(tmp, ARY_HEAP_PTR(ary), VALUE, len); ary_discard(ary); MEMCPY((VALUE *)ARY_EMBED_PTR(ary), tmp, VALUE, len); /* WB: no new reference */ ARY_SET_EMBED_LEN(ary, len); } else { if (olen > len + ARY_DEFAULT_SIZE) { SIZED_REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, len, RARRAY(ary)->as.heap.aux.capa); ARY_SET_CAPA(ary, len); } ARY_SET_HEAP_LEN(ary, len); } return ary; } /* * call-seq: * ary[index] = obj -> obj * ary[start, length] = obj or other_ary or nil -> obj or other_ary or nil * ary[range] = obj or other_ary or nil -> obj or other_ary or nil * * Element Assignment --- Sets the element at +index+, or replaces a subarray * from the +start+ index for +length+ elements, or replaces a subarray * specified by the +range+ of indices. * * If indices are greater than the current capacity of the array, the array * grows automatically. Elements are inserted into the array at +start+ if * +length+ is zero. * * Negative indices will count backward from the end of the array. For * +start+ and +range+ cases the starting index is just before an element. * * 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"] * a[0, 0] = [ 1, 2 ] #=> [1, 2, "A"] * a[3, 0] = "B" #=> [1, 2, "A", "B"] */ static VALUE rb_ary_aset(int argc, VALUE *argv, VALUE ary) { long offset, beg, len; VALUE rpl; if (argc == 3) { rb_ary_modify_check(ary); beg = NUM2LONG(argv[0]); len = NUM2LONG(argv[1]); goto range; } rb_check_arity(argc, 2, 2); rb_ary_modify_check(ary); 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 */ range: rpl = rb_ary_to_ary(argv[argc-1]); rb_ary_splice(ary, beg, len, RARRAY_CONST_PTR(rpl), RARRAY_LEN(rpl)); RB_GC_GUARD(rpl); return argv[argc-1]; } offset = NUM2LONG(argv[0]); fixnum: rb_ary_store(ary, offset, argv[1]); return argv[1]; } /* * call-seq: * ary.insert(index, obj...) -> ary * * Inserts the given values before the element with the given +index+. * * Negative indices count backwards from the end of the array, where +-1+ is * the last element. If a negative index is used, the given values will be * inserted after that element, so using an index of +-1+ will insert the * values at the end of the array. * * 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; rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); rb_ary_modify_check(ary); pos = NUM2LONG(argv[0]); if (argc == 1) return ary; if (pos == -1) { pos = RARRAY_LEN(ary); } else if (pos < 0) { long minpos = -RARRAY_LEN(ary) - 1; if (pos < minpos) { rb_raise(rb_eIndexError, "index %ld too small for array; minimum: %ld", pos, minpos); } pos++; } rb_ary_splice(ary, pos, 0, argv + 1, argc - 1); return ary; } static VALUE rb_ary_length(VALUE ary); static VALUE ary_enum_length(VALUE ary, VALUE args, VALUE eobj) { return rb_ary_length(ary); } /* * call-seq: * ary.each { |item| block } -> ary * ary.each -> Enumerator * * Calls the given block once for each element in +self+, passing that element * as a parameter. Returns the array itself. * * If no block is given, an Enumerator is returned. * * a = [ "a", "b", "c" ] * a.each {|x| print x, " -- " } * * produces: * * a -- b -- c -- */ VALUE rb_ary_each(VALUE ary) { long i; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); for (i=0; i ary * ary.each_index -> Enumerator * * Same as Array#each, but passes the +index+ of the element instead of the * element itself. * * An Enumerator is returned if no block is given. * * 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_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); for (i=0; i ary * ary.reverse_each -> Enumerator * * Same as Array#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_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); len = RARRAY_LEN(ary); while (len--) { long nlen; rb_yield(RARRAY_AREF(ary, len)); nlen = RARRAY_LEN(ary); if (nlen < len) { len = nlen; } } return ary; } /* * call-seq: * ary.length -> int * * Returns the number of elements in +self+. May be zero. * * [ 1, 2, 3, 4, 5 ].length #=> 5 * [].length #=> 0 */ static VALUE rb_ary_length(VALUE ary) { long len = RARRAY_LEN(ary); return LONG2NUM(len); } /* * call-seq: * ary.empty? -> true or false * * Returns +true+ if +self+ 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) { long len = RARRAY_LEN(ary); VALUE dup = rb_ary_new2(len); ary_memcpy(dup, 0, len, RARRAY_CONST_PTR(ary)); ARY_SET_LEN(dup, len); return dup; } VALUE rb_ary_resurrect(VALUE ary) { return rb_ary_new4(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary)); } extern VALUE rb_output_fs; static void ary_join_1(VALUE obj, VALUE ary, VALUE sep, long i, VALUE result, int *first); static VALUE recursive_join(VALUE obj, VALUE argp, int recur) { VALUE *arg = (VALUE *)argp; VALUE ary = arg[0]; VALUE sep = arg[1]; VALUE result = arg[2]; int *first = (int *)arg[3]; if (recur) { rb_raise(rb_eArgError, "recursive array join"); } else { ary_join_1(obj, ary, sep, 0, result, first); } return Qnil; } static void ary_join_0(VALUE ary, VALUE sep, long max, VALUE result) { long i; VALUE val; if (max > 0) rb_enc_copy(result, RARRAY_AREF(ary, 0)); for (i=0; i 0 && !NIL_P(sep)) rb_str_buf_append(result, sep); rb_str_buf_append(result, val); if (OBJ_TAINTED(val)) OBJ_TAINT(result); } } static void ary_join_1(VALUE obj, VALUE ary, VALUE sep, long i, VALUE result, int *first) { VALUE val, tmp; for (; i 0 && !NIL_P(sep)) rb_str_buf_append(result, sep); val = RARRAY_AREF(ary, i); if (RB_TYPE_P(val, T_STRING)) { str_join: rb_str_buf_append(result, val); *first = FALSE; } else if (RB_TYPE_P(val, T_ARRAY)) { obj = val; ary_join: if (val == ary) { rb_raise(rb_eArgError, "recursive array join"); } else { VALUE args[4]; args[0] = val; args[1] = sep; args[2] = result; args[3] = (VALUE)first; rb_exec_recursive(recursive_join, obj, (VALUE)args); } } else { tmp = rb_check_string_type(val); if (!NIL_P(tmp)) { val = tmp; goto str_join; } tmp = rb_check_convert_type_with_id(val, T_ARRAY, "Array", idTo_ary); if (!NIL_P(tmp)) { obj = val; val = tmp; goto ary_join; } val = rb_obj_as_string(val); if (*first) { rb_enc_copy(result, val); *first = FALSE; } goto str_join; } } } VALUE rb_ary_join(VALUE ary, VALUE sep) { long len = 1, i; int taint = FALSE; VALUE val, tmp, result; if (RARRAY_LEN(ary) == 0) return rb_usascii_str_new(0, 0); if (OBJ_TAINTED(ary)) taint = TRUE; if (!NIL_P(sep)) { StringValue(sep); len += RSTRING_LEN(sep) * (RARRAY_LEN(ary) - 1); } for (i=0; i str * * Returns a string created by converting each element of the array to * a string, separated by the given +separator+. * If the +separator+ is +nil+, it uses current $,. * If both the +separator+ and $, are +nil+, * it uses an empty string. * * [ "a", "b", "c" ].join #=> "abc" * [ "a", "b", "c" ].join("-") #=> "a-b-c" * * For nested arrays, join is applied recursively: * * [ "a", [1, 2, [:x, :y]], "b" ].join("-") #=> "a-1-2-x-y-b" */ 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); long i; VALUE s, str; if (recur) return rb_usascii_str_new_cstr("[...]"); str = rb_str_buf_new2("["); for (i=0; i 0) rb_str_buf_cat2(str, ", "); else rb_enc_copy(str, s); rb_str_buf_append(str, s); } rb_str_buf_cat2(str, "]"); if (tainted) OBJ_TAINT(str); return str; } /* * call-seq: * ary.inspect -> string * ary.to_s -> string * * Creates a string representation of +self+. * * [ "a", "b", "c" ].to_s #=> "[\"a\", \"b\", \"c\"]" */ 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: * ary.to_a -> ary * * 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: * ary.to_h -> hash * * Returns the result of interpreting ary as an array of * [key, value] pairs. * * [[:foo, :bar], [1, 2]].to_h * # => {:foo => :bar, 1 => 2} */ static VALUE rb_ary_to_h(VALUE ary) { long i; VALUE hash = rb_hash_new(); for (i=0; i ary * * Returns +self+. */ static VALUE rb_ary_to_ary_m(VALUE ary) { return ary; } static void ary_reverse(VALUE *p1, VALUE *p2) { while (p1 < p2) { VALUE tmp = *p1; *p1++ = *p2; *p2-- = tmp; } } VALUE rb_ary_reverse(VALUE ary) { VALUE *p2; long len = RARRAY_LEN(ary); rb_ary_modify(ary); if (len > 1) { RARRAY_PTR_USE(ary, p1, { p2 = p1 + len - 1; /* points last item */ ary_reverse(p1, p2); }); /* WB: no new reference */ } return ary; } /* * call-seq: * ary.reverse! -> ary * * 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: * ary.reverse -> new_ary * * 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) { long len = RARRAY_LEN(ary); VALUE dup = rb_ary_new2(len); if (len > 0) { const VALUE *p1 = RARRAY_CONST_PTR(ary); VALUE *p2 = (VALUE *)RARRAY_CONST_PTR(dup) + len - 1; do *p2-- = *p1++; while (--len > 0); } ARY_SET_LEN(dup, RARRAY_LEN(ary)); return dup; } static inline long rotate_count(long cnt, long len) { return (cnt < 0) ? (len - (~cnt % len) - 1) : (cnt % len); } VALUE rb_ary_rotate(VALUE ary, long cnt) { rb_ary_modify(ary); if (cnt != 0) { VALUE *ptr = RARRAY_PTR(ary); long len = RARRAY_LEN(ary); if (len > 0 && (cnt = rotate_count(cnt, len)) > 0) { --len; if (cnt < len) ary_reverse(ptr + cnt, ptr + len); if (--cnt > 0) ary_reverse(ptr, ptr + cnt); if (len > 0) ary_reverse(ptr, ptr + len); return ary; } } return Qnil; } /* * call-seq: * ary.rotate!(count=1) -> ary * * Rotates +self+ in place so that the element at +count+ comes first, and * returns +self+. * * If +count+ is negative then it rotates in the opposite direction, starting * from the end of the array where +-1+ is the last element. * * a = [ "a", "b", "c", "d" ] * a.rotate! #=> ["b", "c", "d", "a"] * a #=> ["b", "c", "d", "a"] * a.rotate!(2) #=> ["d", "a", "b", "c"] * a.rotate!(-3) #=> ["a", "b", "c", "d"] */ static VALUE rb_ary_rotate_bang(int argc, VALUE *argv, VALUE ary) { long n = 1; switch (argc) { case 1: n = NUM2LONG(argv[0]); case 0: break; default: rb_scan_args(argc, argv, "01", NULL); } rb_ary_rotate(ary, n); return ary; } /* * call-seq: * ary.rotate(count=1) -> new_ary * * Returns a new array by rotating +self+ so that the element at +count+ is * the first element of the new array. * * If +count+ is negative then it rotates in the opposite direction, starting * from the end of +self+ where +-1+ is the last element. * * a = [ "a", "b", "c", "d" ] * a.rotate #=> ["b", "c", "d", "a"] * a #=> ["a", "b", "c", "d"] * a.rotate(2) #=> ["c", "d", "a", "b"] * a.rotate(-3) #=> ["b", "c", "d", "a"] */ static VALUE rb_ary_rotate_m(int argc, VALUE *argv, VALUE ary) { VALUE rotated; const VALUE *ptr; long len, cnt = 1; switch (argc) { case 1: cnt = NUM2LONG(argv[0]); case 0: break; default: rb_scan_args(argc, argv, "01", NULL); } len = RARRAY_LEN(ary); rotated = rb_ary_new2(len); if (len > 0) { cnt = rotate_count(cnt, len); ptr = RARRAY_CONST_PTR(ary); len -= cnt; ary_memcpy(rotated, 0, len, ptr + cnt); ary_memcpy(rotated, len, cnt, ptr); } ARY_SET_LEN(rotated, RARRAY_LEN(ary)); return rotated; } struct ary_sort_data { VALUE ary; struct cmp_opt_data cmp_opt; }; 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; VALUE args[2]; int n; args[0] = a; args[1] = b; retval = rb_yield_values2(2, args); 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) && CMP_OPTIMIZABLE(data->cmp_opt, Fixnum)) { if ((long)a > (long)b) return 1; if ((long)a < (long)b) return -1; return 0; } if (STRING_P(a) && STRING_P(b) && CMP_OPTIMIZABLE(data->cmp_opt, String)) { return rb_str_cmp(a, b); } if (RB_FLOAT_TYPE_P(a) && CMP_OPTIMIZABLE(data->cmp_opt, Float)) { return rb_float_cmp(a, b); } retval = rb_funcallv(a, id_cmp, 1, &b); n = rb_cmpint(retval, a, b); sort_reentered(data->ary); return n; } /* * call-seq: * ary.sort! -> ary * ary.sort! { |a, b| block } -> ary * * Sorts +self+ in place. * * Comparisons for the sort will be done using the <=> operator * or using an optional code block. * * The block must implement a comparison between +a+ and +b+ and return * an integer less than 0 when +b+ follows +a+, +0+ when +a+ and +b+ * are equivalent, or an integer greater than 0 when +a+ follows +b+. * * The result is not guaranteed to be stable. When the comparison of two * elements returns +0+, the order of the elements is unpredictable. * * ary = [ "d", "a", "e", "c", "b" ] * ary.sort! #=> ["a", "b", "c", "d", "e"] * ary.sort! { |a, b| b <=> a } #=> ["e", "d", "c", "b", "a"] * * See also Enumerable#sort_by. */ 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; long len = RARRAY_LEN(ary); RBASIC_CLEAR_CLASS(tmp); data.ary = tmp; data.cmp_opt.opt_methods = 0; data.cmp_opt.opt_inited = 0; RARRAY_PTR_USE(tmp, ptr, { ruby_qsort(ptr, len, sizeof(VALUE), rb_block_given_p()?sort_1:sort_2, &data); }); /* WB: no new reference */ rb_ary_modify(ary); if (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); } ary_memcpy(ary, 0, ARY_EMBED_LEN(tmp), ARY_EMBED_PTR(tmp)); ARY_SET_LEN(ary, ARY_EMBED_LEN(tmp)); } else { if (!ARY_EMBED_P(ary) && ARY_HEAP_PTR(ary) == ARY_HEAP_PTR(tmp)) { FL_UNSET_SHARED(ary); ARY_SET_CAPA(ary, RARRAY_LEN(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 { ruby_sized_xfree((void *)ARY_HEAP_PTR(ary), ARY_HEAP_SIZE(ary)); } ARY_SET_PTR(ary, RARRAY_CONST_PTR(tmp)); ARY_SET_HEAP_LEN(ary, len); ARY_SET_CAPA(ary, RARRAY_LEN(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_SET_CLASS_RAW(tmp, rb_cArray); /* rb_cArray must be marked */ } return ary; } /* * call-seq: * ary.sort -> new_ary * ary.sort { |a, b| block } -> new_ary * * 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 must implement a comparison between +a+ and +b+ and return * an integer less than 0 when +b+ follows +a+, +0+ when +a+ and +b+ * are equivalent, or an integer greater than 0 when +a+ follows +b+. * * The result is not guaranteed to be stable. When the comparison of two * elements returns +0+, the order of the elements is unpredictable. * * ary = [ "d", "a", "e", "c", "b" ] * ary.sort #=> ["a", "b", "c", "d", "e"] * ary.sort { |a, b| b <=> a } #=> ["e", "d", "c", "b", "a"] * * See also Enumerable#sort_by. */ VALUE rb_ary_sort(VALUE ary) { ary = rb_ary_dup(ary); rb_ary_sort_bang(ary); return ary; } static VALUE rb_ary_bsearch_index(VALUE ary); /* * call-seq: * ary.bsearch {|x| block } -> elem * * By using binary search, finds a value from this array which meets * the given condition in O(log n) where n is the size of the array. * * You can use this method in two use cases: a find-minimum mode and * a find-any mode. In either case, the elements of the array must be * monotone (or sorted) with respect to the block. * * In find-minimum mode (this is a good choice for typical use case), * the block must return true or false, and there must be an index i * (0 <= i <= ary.size) so that: * * - the block returns false for any element whose index is less than * i, and * - the block returns true for any element whose index is greater * than or equal to i. * * This method returns the i-th element. If i is equal to ary.size, * it returns nil. * * ary = [0, 4, 7, 10, 12] * ary.bsearch {|x| x >= 4 } #=> 4 * ary.bsearch {|x| x >= 6 } #=> 7 * ary.bsearch {|x| x >= -1 } #=> 0 * ary.bsearch {|x| x >= 100 } #=> nil * * In find-any mode (this behaves like libc's bsearch(3)), the block * must return a number, and there must be two indices i and j * (0 <= i <= j <= ary.size) so that: * * - the block returns a positive number for ary[k] if 0 <= k < i, * - the block returns zero for ary[k] if i <= k < j, and * - the block returns a negative number for ary[k] if * j <= k < ary.size. * * Under this condition, this method returns any element whose index * is within i...j. If i is equal to j (i.e., there is no element * that satisfies the block), this method returns nil. * * ary = [0, 4, 7, 10, 12] * # try to find v such that 4 <= v < 8 * ary.bsearch {|x| 1 - x / 4 } #=> 4 or 7 * # try to find v such that 8 <= v < 10 * ary.bsearch {|x| 4 - x / 2 } #=> nil * * You must not mix the two modes at a time; the block must always * return either true/false, or always return a number. It is * undefined which value is actually picked up at each iteration. */ static VALUE rb_ary_bsearch(VALUE ary) { VALUE index_result = rb_ary_bsearch_index(ary); if (FIXNUM_P(index_result)) { return rb_ary_entry(ary, FIX2LONG(index_result)); } return index_result; } /* * call-seq: * ary.bsearch_index {|x| block } -> int or nil * * By using binary search, finds an index of a value from this array which * meets the given condition in O(log n) where n is the size of the array. * * It supports two modes, depending on the nature of the block and they are * exactly the same as in the case of #bsearch method with the only difference * being that this method returns the index of the element instead of the * element itself. For more details consult the documentation for #bsearch. */ static VALUE rb_ary_bsearch_index(VALUE ary) { long low = 0, high = RARRAY_LEN(ary), mid; int smaller = 0, satisfied = 0; VALUE v, val; RETURN_ENUMERATOR(ary, 0, 0); while (low < high) { mid = low + ((high - low) / 2); val = rb_ary_entry(ary, mid); v = rb_yield(val); if (FIXNUM_P(v)) { if (v == INT2FIX(0)) return INT2FIX(mid); smaller = (SIGNED_VALUE)v < 0; /* Fixnum preserves its sign-bit */ } else if (v == Qtrue) { satisfied = 1; smaller = 1; } else if (v == Qfalse || v == Qnil) { smaller = 0; } else if (rb_obj_is_kind_of(v, rb_cNumeric)) { const VALUE zero = INT2FIX(0); switch (rb_cmpint(rb_funcallv(v, id_cmp, 1, &zero), v, zero)) { case 0: return INT2FIX(mid); case 1: smaller = 1; break; case -1: smaller = 0; } } else { rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE " (must be numeric, true, false or nil)", rb_obj_class(v)); } if (smaller) { high = mid; } else { low = mid + 1; } } if (!satisfied) return Qnil; return INT2FIX(low); } static VALUE sort_by_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, dummy)) { return rb_yield(i); } /* * call-seq: * ary.sort_by! { |obj| block } -> ary * ary.sort_by! -> Enumerator * * Sorts +self+ in place using a set of keys generated by mapping the * values in +self+ through the given block. * * The result is not guaranteed to be stable. When two keys are equal, * the order of the corresponding elements is unpredictable. * * If no block is given, an Enumerator is returned instead. * * See also Enumerable#sort_by. */ static VALUE rb_ary_sort_by_bang(VALUE ary) { VALUE sorted; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); rb_ary_modify(ary); sorted = rb_block_call(ary, rb_intern("sort_by"), 0, 0, sort_by_i, 0); rb_ary_replace(ary, sorted); return ary; } /* * call-seq: * ary.collect { |item| block } -> new_ary * ary.map { |item| block } -> new_ary * ary.collect -> Enumerator * ary.map -> Enumerator * * Invokes the given block once for each element of +self+. * * Creates a new array containing the values returned by the block. * * See also Enumerable#collect. * * If no block is given, an Enumerator is returned instead. * * a = [ "a", "b", "c", "d" ] * a.collect { |x| x + "!" } #=> ["a!", "b!", "c!", "d!"] * a.map.with_index { |x, i| x * i } #=> ["", "b", "cc", "ddd"] * a #=> ["a", "b", "c", "d"] */ static VALUE rb_ary_collect(VALUE ary) { long i; VALUE collect; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); collect = rb_ary_new2(RARRAY_LEN(ary)); for (i = 0; i < RARRAY_LEN(ary); i++) { rb_ary_push(collect, rb_yield(RARRAY_AREF(ary, i))); } return collect; } /* * call-seq: * ary.collect! {|item| block } -> ary * ary.map! {|item| block } -> ary * ary.collect! -> Enumerator * ary.map! -> Enumerator * * Invokes the given block once for each element of +self+, replacing the * element with the value returned by the block. * * See also Enumerable#collect. * * If no block is given, an Enumerator is returned instead. * * a = [ "a", "b", "c", "d" ] * a.map! {|x| x + "!" } * a #=> [ "a!", "b!", "c!", "d!" ] * a.collect!.with_index {|x, i| x[0...i] } * a #=> ["", "b", "c!", "d!"] */ static VALUE rb_ary_collect_bang(VALUE ary) { long i; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); rb_ary_modify(ary); for (i = 0; i < RARRAY_LEN(ary); i++) { rb_ary_store(ary, i, rb_yield(RARRAY_AREF(ary, i))); } return ary; } VALUE rb_get_values_at(VALUE obj, long olen, int argc, const VALUE *argv, VALUE (*func) (VALUE, long)) { VALUE result = rb_ary_new2(argc); long beg, len, i, j; for (i=0; i j) rb_ary_resize(result, RARRAY_LEN(result) + (beg + len) - j); continue; } rb_ary_push(result, (*func)(obj, NUM2LONG(argv[i]))); } return result; } /* * call-seq: * ary.values_at(selector, ...) -> new_ary * * 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) # => ["b", "d", "f"] * a.values_at(1, 3, 5, 7) # => ["b", "d", "f", nil] * a.values_at(-1, -2, -2, -7) # => ["f", "e", "e", nil] * a.values_at(4..6, 3...6) # => ["e", "f", nil, "d", "e", "f"] */ 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: * ary.select { |item| block } -> new_ary * ary.select -> Enumerator * * Returns a new array containing all elements of +ary+ * for which the given +block+ returns a true value. * * If no block is given, an Enumerator is returned instead. * * [1,2,3,4,5].select { |num| num.even? } #=> [2, 4] * * a = %w{ a b c d e f } * a.select { |v| v =~ /[aeiou]/ } #=> ["a", "e"] * * See also Enumerable#select. */ static VALUE rb_ary_select(VALUE ary) { VALUE result; long i; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); result = rb_ary_new2(RARRAY_LEN(ary)); for (i = 0; i < RARRAY_LEN(ary); i++) { if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) { rb_ary_push(result, rb_ary_elt(ary, i)); } } return result; } struct select_bang_arg { VALUE ary; long len[2]; }; static VALUE select_bang_i(VALUE a) { volatile struct select_bang_arg *arg = (void *)a; VALUE ary = arg->ary; long i1, i2; for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); arg->len[0] = ++i1) { VALUE v = RARRAY_AREF(ary, i1); if (!RTEST(rb_yield(v))) continue; if (i1 != i2) { rb_ary_store(ary, i2, v); } arg->len[1] = ++i2; } return (i1 == i2) ? Qnil : ary; } static VALUE select_bang_ensure(VALUE a) { volatile struct select_bang_arg *arg = (void *)a; VALUE ary = arg->ary; long len = RARRAY_LEN(ary); long i1 = arg->len[0], i2 = arg->len[1]; if (i2 < len && i2 < i1) { long tail = 0; if (i1 < len) { tail = len - i1; RARRAY_PTR_USE(ary, ptr, { MEMMOVE(ptr + i2, ptr + i1, VALUE, tail); }); } ARY_SET_LEN(ary, i2 + tail); } return ary; } /* * call-seq: * ary.select! {|item| block } -> ary or nil * ary.select! -> Enumerator * * Invokes the given block passing in successive elements from +self+, * deleting elements for which the block returns a +false+ value. * * The array may not be changed instantly every time the block is called. * * If changes were made, it will return +self+, otherwise it returns +nil+. * * See also Array#keep_if * * If no block is given, an Enumerator is returned instead. * */ static VALUE rb_ary_select_bang(VALUE ary) { struct select_bang_arg args; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); rb_ary_modify(ary); args.ary = ary; args.len[0] = args.len[1] = 0; return rb_ensure(select_bang_i, (VALUE)&args, select_bang_ensure, (VALUE)&args); } /* * call-seq: * ary.keep_if { |item| block } -> ary * ary.keep_if -> Enumerator * * Deletes every element of +self+ for which the given block evaluates to * +false+. * * See also Array#select! * * If no block is given, an Enumerator is returned instead. * * a = %w{ a b c d e f } * a.keep_if { |v| v =~ /[aeiou]/ } #=> ["a", "e"] */ static VALUE rb_ary_keep_if(VALUE ary) { RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); rb_ary_select_bang(ary); return ary; } static void ary_resize_smaller(VALUE ary, long len) { rb_ary_modify(ary); if (RARRAY_LEN(ary) > len) { ARY_SET_LEN(ary, len); if (len * 2 < ARY_CAPA(ary) && ARY_CAPA(ary) > ARY_DEFAULT_SIZE) { ary_resize_capa(ary, len * 2); } } } /* * call-seq: * ary.delete(obj) -> item or nil * ary.delete(obj) { block } -> item or result of block * * Deletes all items from +self+ that are equal to +obj+. * * Returns the last deleted item, or +nil+ if no matching item is found. * * If the optional code block is given, the result of the block is returned if * the item is not found. (To remove +nil+ elements and get an informative * return value, use Array#compact!) * * 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_AREF(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; } ary_resize_smaller(ary, i2); return v; } void rb_ary_delete_same(VALUE ary, VALUE item) { long i1, i2; for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); i1++) { VALUE e = RARRAY_AREF(ary, i1); if (e == item) { continue; } if (i1 != i2) { rb_ary_store(ary, i2, e); } i2++; } if (RARRAY_LEN(ary) == i2) { return; } ary_resize_smaller(ary, i2); } 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_AREF(ary, pos); RARRAY_PTR_USE(ary, ptr, { MEMMOVE(ptr+pos, ptr+pos+1, VALUE, len-pos-1); }); ARY_INCREASE_LEN(ary, -1); return del; } /* * call-seq: * ary.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 = ["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: * ary.slice!(index) -> obj or nil * ary.slice!(start, length) -> new_ary or nil * ary.slice!(range) -> new_ary or nil * * Deletes the element(s) given by an +index+ (optionally up to +length+ * elements) or by a +range+. * * Returns the deleted object (or objects), 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 (argc == 2) { pos = NUM2LONG(argv[0]); len = NUM2LONG(argv[1]); 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_CONST_PTR(ary)+pos); RBASIC_SET_CLASS(arg2, rb_obj_class(ary)); rb_ary_splice(ary, pos, len, 0, 0); return arg2; } if (argc != 1) { /* error report */ rb_scan_args(argc, argv, "11", NULL, NULL); } arg1 = argv[0]; 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)); } static VALUE ary_reject(VALUE orig, VALUE result) { long i; for (i = 0; i < RARRAY_LEN(orig); i++) { VALUE v = RARRAY_AREF(orig, i); if (!RTEST(rb_yield(v))) { rb_ary_push(result, v); } } return result; } static VALUE reject_bang_i(VALUE a) { volatile struct select_bang_arg *arg = (void *)a; VALUE ary = arg->ary; long i1, i2; for (i1 = i2 = 0; i1 < RARRAY_LEN(ary); arg->len[0] = ++i1) { VALUE v = RARRAY_AREF(ary, i1); if (RTEST(rb_yield(v))) continue; if (i1 != i2) { rb_ary_store(ary, i2, v); } arg->len[1] = ++i2; } return (i1 == i2) ? Qnil : ary; } static VALUE ary_reject_bang(VALUE ary) { struct select_bang_arg args; rb_ary_modify_check(ary); args.ary = ary; args.len[0] = args.len[1] = 0; return rb_ensure(reject_bang_i, (VALUE)&args, select_bang_ensure, (VALUE)&args); } /* * call-seq: * ary.reject! { |item| block } -> ary or nil * ary.reject! -> Enumerator * * Deletes every element of +self+ for which the block evaluates to +true+, * if no changes were made returns +nil+. * * The array may not be changed instantly every time the block is called. * * See also Enumerable#reject and Array#delete_if. * * If no block is given, an Enumerator is returned instead. */ static VALUE rb_ary_reject_bang(VALUE ary) { RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); return ary_reject_bang(ary); } /* * call-seq: * ary.reject {|item| block } -> new_ary * ary.reject -> Enumerator * * Returns a new array containing the items in +self+ for which the given * block is not +true+. The ordering of non-rejected elements is maintained. * * See also Array#delete_if * * If no block is given, an Enumerator is returned instead. */ static VALUE rb_ary_reject(VALUE ary) { VALUE rejected_ary; RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); rejected_ary = rb_ary_new(); ary_reject(ary, rejected_ary); return rejected_ary; } /* * call-seq: * ary.delete_if { |item| block } -> ary * ary.delete_if -> Enumerator * * Deletes every element of +self+ for which block evaluates to +true+. * * The array is changed instantly every time the block is called, not after * the iteration is over. * * See also Array#reject! * * If no block is given, an Enumerator is returned instead. * * scores = [ 97, 42, 75 ] * scores.delete_if {|score| score < 80 } #=> [97] */ static VALUE rb_ary_delete_if(VALUE ary) { RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); ary_reject_bang(ary); return ary; } static VALUE take_i(RB_BLOCK_CALL_FUNC_ARGLIST(val, cbarg)) { VALUE *args = (VALUE *)cbarg; 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; if (rb_check_block_call(obj, idEach, 0, 0, take_i, (VALUE)args) == Qundef) rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (must respond to :each)", rb_obj_class(obj)); return result; } /* * call-seq: * ary.zip(arg, ...) -> new_ary * ary.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 ary.size _n_-element arrays, * where _n_ is one more than the count of arguments. * * If the size of any argument is less than the size of the initial array, * +nil+ values are supplied. * * If a block is 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 = RARRAY_LEN(ary); VALUE result = Qnil; for (i=0; i 1) { VALUE work, *tmp; tmp = ALLOCV_N(VALUE, work, argc+1); for (i=0; i new_ary * * 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]] * * If the length of the subarrays don't match, an IndexError is raised. */ 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 ary * ary.initialize_copy(other_ary) -> ary * * Replaces the contents of +self+ with the contents of +other_ary+, * 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) { rb_ary_modify_check(copy); orig = to_ary(orig); if (copy == orig) return copy; if (RARRAY_LEN(orig) <= RARRAY_EMBED_LEN_MAX) { VALUE shared = 0; if (ARY_OWNS_HEAP_P(copy)) { RARRAY_PTR_USE(copy, ptr, ruby_sized_xfree(ptr, ARY_HEAP_SIZE(copy))); } else if (ARY_SHARED_P(copy)) { shared = ARY_SHARED(copy); FL_UNSET_SHARED(copy); } FL_SET_EMBED(copy); ary_memcpy(copy, 0, RARRAY_LEN(orig), RARRAY_CONST_PTR(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)) { RARRAY_PTR_USE(copy, ptr, ruby_sized_xfree(ptr, ARY_HEAP_SIZE(copy))); } else { rb_ary_unshare_safe(copy); } FL_UNSET_EMBED(copy); ARY_SET_PTR(copy, RARRAY_CONST_PTR(orig)); ARY_SET_LEN(copy, RARRAY_LEN(orig)); rb_ary_set_shared(copy, shared); } return copy; } /* * call-seq: * ary.clear -> ary * * Removes all elements from +self+. * * a = [ "a", "b", "c", "d", "e" ] * a.clear #=> [ ] */ VALUE rb_ary_clear(VALUE ary) { rb_ary_modify_check(ary); ARY_SET_LEN(ary, 0); if (ARY_SHARED_P(ary)) { if (!ARY_EMBED_P(ary)) { rb_ary_unshare(ary); FL_SET_EMBED(ary); } } else if (ARY_DEFAULT_SIZE * 2 < ARY_CAPA(ary)) { ary_resize_capa(ary, ARY_DEFAULT_SIZE * 2); } return ary; } /* * call-seq: * ary.fill(obj) -> ary * ary.fill(obj, start [, length]) -> ary * ary.fill(obj, range ) -> ary * ary.fill { |index| block } -> ary * ary.fill(start [, length] ) { |index| block } -> ary * ary.fill(range) { |index| block } -> ary * * 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 the length of the array. * * The last three forms fill the array with the value of the given block, * which is passed the absolute index of each element to be filled. * * Negative values of +start+ count from the end of the array, where +-1+ is * the last element. * * 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 = Qundef, arg1, arg2; long beg = 0, end = 0, len = 0; if (rb_block_given_p()) { 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); } ary_mem_clear(ary, RARRAY_LEN(ary), end - RARRAY_LEN(ary)); ARY_SET_LEN(ary, end); } if (item == Qundef) { VALUE v; long i; for (i=beg; i=RARRAY_LEN(ary)) break; ARY_SET(ary, i, v); } } else { ary_memfill(ary, beg, len, item); } return ary; } /* * call-seq: * ary + other_ary -> new_ary * * 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 ] * a = [ "a", "b", "c" ] * c = a + [ "d", "e", "f" ] * c #=> [ "a", "b", "c", "d", "e", "f" ] * a #=> [ "a", "b", "c" ] * * Note that * x += y * is the same as * x = x + y * This means that it produces a new array. As a consequence, * repeated use of += on arrays can be quite inefficient. * * See also Array#concat. */ VALUE rb_ary_plus(VALUE x, VALUE y) { VALUE z; long len, xlen, ylen; y = to_ary(y); xlen = RARRAY_LEN(x); ylen = RARRAY_LEN(y); len = xlen + ylen; z = rb_ary_new2(len); ary_memcpy(z, 0, xlen, RARRAY_CONST_PTR(x)); ary_memcpy(z, xlen, ylen, RARRAY_CONST_PTR(y)); ARY_SET_LEN(z, len); return z; } static VALUE ary_append(VALUE x, VALUE y) { long n = RARRAY_LEN(y); if (n > 0) { rb_ary_splice(x, RARRAY_LEN(x), 0, RARRAY_CONST_PTR(y), n); } return x; } /* * call-seq: * ary.concat(other_ary1, other_ary2,...) -> ary * * Appends the elements of +other_ary+s to +self+. * * [ "a", "b" ].concat( ["c", "d"] ) #=> [ "a", "b", "c", "d" ] * [ "a" ].concat( ["b"], ["c", "d"] ) #=> [ "a", "b", "c", "d" ] * [ "a" ].concat #=> [ "a" ] * * a = [ 1, 2, 3 ] * a.concat( [ 4, 5 ] ) * a #=> [ 1, 2, 3, 4, 5 ] * * a = [ 1, 2 ] * a.concat(a, a) #=> [1, 2, 1, 2, 1, 2] * * See also Array#+. */ static VALUE rb_ary_concat_multi(int argc, VALUE *argv, VALUE ary) { rb_ary_modify_check(ary); if (argc == 1) { rb_ary_concat(ary, argv[0]); } else if (argc > 1) { int i; VALUE args = rb_ary_tmp_new(argc); for (i = 0; i < argc; i++) { rb_ary_concat(args, argv[i]); } ary_append(ary, args); } return ary; } VALUE rb_ary_concat(VALUE x, VALUE y) { return ary_append(x, to_ary(y)); } /* * call-seq: * ary * int -> new_ary * ary * str -> new_string * * Repetition --- With a String argument, equivalent to * ary.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; const VALUE *ptr; long t, 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); ptr = RARRAY_CONST_PTR(ary); t = RARRAY_LEN(ary); if (0 < t) { ary_memcpy(ary2, 0, t, ptr); while (t <= len/2) { ary_memcpy(ary2, t, t, RARRAY_CONST_PTR(ary2)); t *= 2; } if (t < len) { ary_memcpy(ary2, t, len-t, RARRAY_CONST_PTR(ary2)); } } out: OBJ_INFECT(ary2, ary); return ary2; } /* * call-seq: * ary.assoc(obj) -> element_ary 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_AREF(ary, i)); if (!NIL_P(v) && RARRAY_LEN(v) > 0 && rb_equal(RARRAY_AREF(v, 0), key)) return v; } return Qnil; } /* * call-seq: * ary.rassoc(obj) -> element_ary or nil * * Searches through the array whose elements are also arrays. * * Compares +obj+ with the second element of each contained array using * obj.==. * * Returns the first contained array that matches +obj+. * * 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_AREF(ary, i); if (RB_TYPE_P(v, T_ARRAY) && RARRAY_LEN(v) > 1 && rb_equal(RARRAY_AREF(v, 1), value)) return v; } return Qnil; } static VALUE recursive_equal(VALUE ary1, VALUE ary2, int recur) { long i, len1; const VALUE *p1, *p2; if (recur) return Qtrue; /* Subtle! */ p1 = RARRAY_CONST_PTR(ary1); p2 = RARRAY_CONST_PTR(ary2); len1 = RARRAY_LEN(ary1); for (i = 0; i < len1; i++) { if (*p1 != *p2) { if (rb_equal(*p1, *p2)) { len1 = RARRAY_LEN(ary1); if (len1 != RARRAY_LEN(ary2)) return Qfalse; if (len1 < i) return Qtrue; p1 = RARRAY_CONST_PTR(ary1) + i; p2 = RARRAY_CONST_PTR(ary2) + i; } else { return Qfalse; } } p1++; p2++; } return Qtrue; } /* * call-seq: * ary == other_ary -> 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 +other_ary+. * * [ "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 (!RB_TYPE_P(ary2, T_ARRAY)) { if (!rb_respond_to(ary2, idTo_ary)) { return Qfalse; } return rb_equal(ary2, ary1); } if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse; if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue; 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 +self+ and +other+ are the same object, * or are both arrays with the same content (according to Object#eql?). */ static VALUE rb_ary_eql(VALUE ary1, VALUE ary2) { if (ary1 == ary2) return Qtrue; if (!RB_TYPE_P(ary2, T_ARRAY)) return Qfalse; if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse; if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue; return rb_exec_recursive_paired(recursive_eql, ary1, ary2, ary2); } /* * call-seq: * ary.hash -> integer * * Compute a hash-code for this array. * * Two arrays with the same content will have the same hash code (and will * compare using #eql?). * * See also Object#hash. */ static VALUE rb_ary_hash(VALUE ary) { long i; st_index_t h; VALUE n; h = rb_hash_start(RARRAY_LEN(ary)); h = rb_hash_uint(h, (st_index_t)rb_ary_hash); for (i=0; i true or false * * Returns +true+ if the given +object+ is present in +self+ (that is, if any * element == +object+), otherwise returns +false+. * * a = [ "a", "b", "c" ] * a.include?("b") #=> true * a.include?("z") #=> false */ VALUE rb_ary_includes(VALUE ary, VALUE item) { long i; VALUE e; for (i=0; i RARRAY_LEN(ary2)) { len = RARRAY_LEN(ary2); } for (i=0; i other_ary -> -1, 0, +1 or nil * * Comparison --- Returns an integer (+-1+, +0+, or +1) if this * array is less than, equal to, or greater than +other_ary+. * * Each object in each array is compared (using the <=> operator). * * Arrays are compared in an "element-wise" manner; the first element of +ary+ * is compared with the first one of +other_ary+ using the <=> operator, then * each of the second elements, etc... * As soon as the result of any such comparison is non zero (i.e. the two * corresponding elements are not equal), that result is returned for the * whole array comparison. * * If all the elements are equal, then the result 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. * * +nil+ is returned if the +other_ary+ is not an array or if the comparison * of two elements returned +nil+. * * [ "a", "a", "c" ] <=> [ "a", "b", "c" ] #=> -1 * [ 1, 2, 3, 4, 5, 6 ] <=> [ 1, 2 ] #=> +1 * [ 1, 2 ] <=> [ 1, :two ] #=> nil * */ VALUE rb_ary_cmp(VALUE ary1, VALUE ary2) { long len; VALUE v; ary2 = rb_check_array_type(ary2); if (NIL_P(ary2)) return Qnil; 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_add_hash(VALUE hash, VALUE ary) { long i; for (i=0; intbl) { st_table *tbl = RHASH(hash)->ntbl; st_free_table(tbl); } rb_gc_force_recycle(hash); } /* * call-seq: * ary - other_ary -> new_ary * * Array Difference * * Returns a new array that is a copy of the original array, removing any * items that also appear in +other_ary+. The order is preserved from the * original array. * * It compares elements using their #hash and #eql? methods for efficiency. * * [ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ] #=> [ 3, 3, 5 ] * * If you need set-like behavior, see the library class Set. */ static VALUE rb_ary_diff(VALUE ary1, VALUE ary2) { VALUE ary3; VALUE hash; long i; hash = ary_make_hash(to_ary(ary2)); ary3 = rb_ary_new(); for (i=0; i new_ary * * Set Intersection --- Returns a new array containing unique elements common to the * two arrays. The order is preserved from the original array. * * It compares elements using their #hash and #eql? methods for efficiency. * * [ 1, 1, 3, 5 ] & [ 3, 2, 1 ] #=> [ 1, 3 ] * [ 'a', 'b', 'b', 'z' ] & [ 'a', 'b', 'c' ] #=> [ 'a', 'b' ] * * See also Array#uniq. */ static VALUE rb_ary_and(VALUE ary1, VALUE ary2) { VALUE hash, ary3, v; st_table *table; st_data_t vv; long i; ary2 = to_ary(ary2); ary3 = rb_ary_new(); if (RARRAY_LEN(ary2) == 0) return ary3; hash = ary_make_hash(ary2); table = rb_hash_tbl_raw(hash); for (i=0; i new_ary * * Set Union --- Returns a new array by joining +ary+ with +other_ary+, * excluding any duplicates and preserving the order from the given arrays. * * It compares elements using their #hash and #eql? methods for efficiency. * * [ "a", "b", "c" ] | [ "c", "d", "a" ] #=> [ "a", "b", "c", "d" ] * [ "c", "d", "a" ] | [ "a", "b", "c" ] #=> [ "c", "d", "a", "b" ] * * See also Array#uniq. */ static VALUE rb_ary_or(VALUE ary1, VALUE ary2) { VALUE hash, ary3; long i; ary2 = to_ary(ary2); hash = ary_make_hash(ary1); for (i=0; i obj * ary.max { |a, b| block } -> obj * ary.max(n) -> array * ary.max(n) { |a, b| block } -> array * * Returns the object in _ary_ with the maximum value. The * first form assumes all objects implement Comparable; * the second uses the block to return a <=> b. * * a = %w(albatross dog horse) * a.max #=> "horse" * a.max { |a, b| a.length <=> b.length } #=> "albatross" * * If the +n+ argument is given, maximum +n+ elements are returned * as an array. * * a = %w[albatross dog horse] * a.max(2) #=> ["horse", "dog"] * a.max(2) {|a, b| a.length <=> b.length } #=> ["albatross", "horse"] */ static VALUE rb_ary_max(int argc, VALUE *argv, VALUE ary) { struct cmp_opt_data cmp_opt = { 0, 0 }; VALUE result = Qundef, v; VALUE num; long i; rb_scan_args(argc, argv, "01", &num); if (!NIL_P(num)) return rb_nmin_run(ary, num, 0, 1, 1); if (rb_block_given_p()) { for (i = 0; i < RARRAY_LEN(ary); i++) { v = RARRAY_AREF(ary, i); if (result == Qundef || rb_cmpint(rb_yield_values(2, v, result), v, result) > 0) { result = v; } } } else { for (i = 0; i < RARRAY_LEN(ary); i++) { v = RARRAY_AREF(ary, i); if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) > 0) { result = v; } } } if (result == Qundef) return Qnil; return result; } /* * call-seq: * ary.min -> obj * ary.min {| a,b | block } -> obj * ary.min(n) -> array * ary.min(n) {| a,b | block } -> array * * Returns the object in _ary_ with the minimum value. The * first form assumes all objects implement Comparable; * the second uses the block to return a <=> b. * * a = %w(albatross dog horse) * a.min #=> "albatross" * a.min { |a, b| a.length <=> b.length } #=> "dog" * * If the +n+ argument is given, minimum +n+ elements are returned * as an array. * * a = %w[albatross dog horse] * a.min(2) #=> ["albatross", "dog"] * a.min(2) {|a, b| a.length <=> b.length } #=> ["dog", "horse"] */ static VALUE rb_ary_min(int argc, VALUE *argv, VALUE ary) { struct cmp_opt_data cmp_opt = { 0, 0 }; VALUE result = Qundef, v; VALUE num; long i; rb_scan_args(argc, argv, "01", &num); if (!NIL_P(num)) return rb_nmin_run(ary, num, 0, 0, 1); if (rb_block_given_p()) { for (i = 0; i < RARRAY_LEN(ary); i++) { v = RARRAY_AREF(ary, i); if (result == Qundef || rb_cmpint(rb_yield_values(2, v, result), v, result) < 0) { result = v; } } } else { for (i = 0; i < RARRAY_LEN(ary); i++) { v = RARRAY_AREF(ary, i); if (result == Qundef || OPTIMIZED_CMP(v, result, cmp_opt) < 0) { result = v; } } } if (result == Qundef) return Qnil; return result; } static int push_value(st_data_t key, st_data_t val, st_data_t ary) { rb_ary_push((VALUE)ary, (VALUE)val); return ST_CONTINUE; } /* * call-seq: * ary.uniq! -> ary or nil * ary.uniq! { |item| ... } -> ary or nil * * Removes duplicate elements from +self+. * * If a block is given, it will use the return value of the block for * comparison. * * It compares values using their #hash and #eql? methods for efficiency. * * +self+ is traversed in order, and the first occurrence is kept. * * 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 * * c = [["student","sam"], ["student","george"], ["teacher","matz"]] * c.uniq! { |s| s.first } # => [["student", "sam"], ["teacher", "matz"]] * */ static VALUE rb_ary_uniq_bang(VALUE ary) { VALUE hash; long hash_size; rb_ary_modify_check(ary); if (RARRAY_LEN(ary) <= 1) return Qnil; if (rb_block_given_p()) hash = ary_make_hash_by(ary); else hash = ary_make_hash(ary); hash_size = RHASH_SIZE(hash); if (RARRAY_LEN(ary) == hash_size) { return Qnil; } rb_ary_modify_check(ary); ARY_SET_LEN(ary, 0); if (ARY_SHARED_P(ary) && !ARY_EMBED_P(ary)) { rb_ary_unshare(ary); FL_SET_EMBED(ary); } ary_resize_capa(ary, hash_size); st_foreach(rb_hash_tbl_raw(hash), push_value, ary); ary_recycle_hash(hash); return ary; } /* * call-seq: * ary.uniq -> new_ary * ary.uniq { |item| ... } -> new_ary * * Returns a new array by removing duplicate values in +self+. * * If a block is given, it will use the return value of the block for comparison. * * It compares values using their #hash and #eql? methods for efficiency. * * +self+ is traversed in order, and the first occurrence is kept. * * a = [ "a", "a", "b", "b", "c" ] * a.uniq # => ["a", "b", "c"] * * b = [["student","sam"], ["student","george"], ["teacher","matz"]] * b.uniq { |s| s.first } # => [["student", "sam"], ["teacher", "matz"]] * */ static VALUE rb_ary_uniq(VALUE ary) { VALUE hash, uniq; if (RARRAY_LEN(ary) <= 1) return rb_ary_dup(ary); if (rb_block_given_p()) { hash = ary_make_hash_by(ary); uniq = rb_hash_values(hash); } else { hash = ary_make_hash(ary); uniq = rb_hash_values(hash); } RBASIC_SET_CLASS(uniq, rb_obj_class(ary)); ary_recycle_hash(hash); return uniq; } /* * call-seq: * ary.compact! -> ary or nil * * Removes +nil+ elements from the array. * * Returns +nil+ if no changes were made, otherwise returns the array. * * [ "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 = (VALUE *)RARRAY_CONST_PTR(ary); /* WB: no new reference */ end = p + RARRAY_LEN(ary); while (t < end) { if (NIL_P(*t)) t++; else *p++ = *t++; } n = p - RARRAY_CONST_PTR(ary); if (RARRAY_LEN(ary) == n) { return Qnil; } ary_resize_smaller(ary, n); return ary; } /* * call-seq: * ary.compact -> new_ary * * 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: * ary.count -> int * ary.count(obj) -> int * ary.count { |item| block } -> int * * Returns the number of elements. * * If an argument is given, counts the number of elements which equal +obj+ * using ==. * * If a block is given, counts the number of elements for which the block * returns 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 i, n = 0; if (argc == 0) { VALUE v; if (!rb_block_given_p()) return LONG2NUM(RARRAY_LEN(ary)); for (i = 0; i < RARRAY_LEN(ary); i++) { v = RARRAY_AREF(ary, i); if (RTEST(rb_yield(v))) n++; } } else { VALUE obj; rb_scan_args(argc, argv, "1", &obj); if (rb_block_given_p()) { rb_warn("given block not used"); } for (i = 0; i < RARRAY_LEN(ary); i++) { if (rb_equal(RARRAY_AREF(ary, i), 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_AREF(ary, i++); if (level >= 0 && RARRAY_LEN(stack) / 2 >= level) { rb_ary_push(result, elt); continue; } tmp = rb_check_array_type(elt); if (RBASIC(result)->klass) { rb_raise(rb_eRuntimeError, "flatten reentered"); } if (NIL_P(tmp)) { 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_SET_CLASS(result, rb_obj_class(ary)); return result; } /* * call-seq: * ary.flatten! -> ary or nil * ary.flatten!(level) -> ary or nil * * Flattens +self+ in place. * * Returns +nil+ if no modifications were made (i.e., the array contains no * subarrays.) * * 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); rb_ary_modify_check(ary); if (!NIL_P(lv)) level = NUM2INT(lv); if (level == 0) return Qnil; result = flatten(ary, level, &mod); if (mod == 0) { ary_discard(result); return Qnil; } if (!(mod = ARY_EMBED_P(result))) rb_obj_freeze(result); rb_ary_replace(ary, result); if (mod) ARY_SET_EMBED_LEN(result, 0); return ary; } /* * call-seq: * ary.flatten -> new_ary * ary.flatten(level) -> new_ary * * Returns a new array that is a one-dimensional flattening of +self+ * (recursively). * * That is, for every element that is an array, extract its elements into * the new array. * * 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; } #define OPTHASH_GIVEN_P(opts) \ (argc > 0 && !NIL_P((opts) = rb_check_hash_type(argv[argc-1])) && (--argc, 1)) static ID id_random; #define RAND_UPTO(max) (long)rb_random_ulong_limited((randgen), (max)-1) /* * call-seq: * ary.shuffle! -> ary * ary.shuffle!(random: rng) -> ary * * Shuffles elements in +self+ in place. * * a = [ 1, 2, 3 ] #=> [1, 2, 3] * a.shuffle! #=> [2, 3, 1] * a #=> [2, 3, 1] * * The optional +rng+ argument will be used as the random number generator. * * a.shuffle!(random: Random.new(1)) #=> [1, 3, 2] */ static VALUE rb_ary_shuffle_bang(int argc, VALUE *argv, VALUE ary) { VALUE opts, randgen = rb_cRandom; long i, len; if (OPTHASH_GIVEN_P(opts)) { VALUE rnd; ID keyword_ids[1]; keyword_ids[0] = id_random; rb_get_kwargs(opts, keyword_ids, 0, 1, &rnd); if (rnd != Qundef) { randgen = rnd; } } rb_check_arity(argc, 0, 0); rb_ary_modify(ary); i = len = RARRAY_LEN(ary); RARRAY_PTR_USE(ary, ptr, { while (i) { long j = RAND_UPTO(i); VALUE tmp; if (len != RARRAY_LEN(ary) || ptr != RARRAY_CONST_PTR(ary)) { rb_raise(rb_eRuntimeError, "modified during shuffle"); } tmp = ptr[--i]; ptr[i] = ptr[j]; ptr[j] = tmp; } }); /* WB: no new reference */ return ary; } /* * call-seq: * ary.shuffle -> new_ary * ary.shuffle(random: rng) -> new_ary * * Returns a new array with elements of +self+ shuffled. * * a = [ 1, 2, 3 ] #=> [1, 2, 3] * a.shuffle #=> [2, 3, 1] * a #=> [1, 2, 3] * * The optional +rng+ argument will be used as the random number generator. * * a.shuffle(random: Random.new(1)) #=> [1, 3, 2] */ static VALUE rb_ary_shuffle(int argc, VALUE *argv, VALUE ary) { ary = rb_ary_dup(ary); rb_ary_shuffle_bang(argc, argv, ary); return ary; } /* * call-seq: * ary.sample -> obj * ary.sample(random: rng) -> obj * ary.sample(n) -> new_ary * ary.sample(n, random: rng) -> new_ary * * Choose a random element or +n+ random elements from the array. * * The elements are chosen by using random and unique indices into the array * in order to ensure that an element doesn't repeat itself unless the array * already contained duplicate elements. * * If the array is empty the first form returns +nil+ and the second form * returns an empty array. * * The optional +rng+ argument will be used as the random number generator. * * a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] * a.sample #=> 7 * a.sample(4) #=> [6, 4, 2, 5] */ static VALUE rb_ary_sample(int argc, VALUE *argv, VALUE ary) { VALUE nv, result; VALUE opts, randgen = rb_cRandom; long n, len, i, j, k, idx[10]; long rnds[numberof(idx)]; long memo_threshold; if (OPTHASH_GIVEN_P(opts)) { VALUE rnd; ID keyword_ids[1]; keyword_ids[0] = id_random; rb_get_kwargs(opts, keyword_ids, 0, 1, &rnd); if (rnd != Qundef) { randgen = rnd; } } len = RARRAY_LEN(ary); if (argc == 0) { if (len < 2) i = 0; else i = RAND_UPTO(len); return rb_ary_elt(ary, i); } rb_scan_args(argc, argv, "1", &nv); n = NUM2LONG(nv); if (n < 0) rb_raise(rb_eArgError, "negative sample number"); if (n > len) n = len; if (n <= numberof(idx)) { for (i = 0; i < n; ++i) { rnds[i] = RAND_UPTO(len - i); } } k = len; len = RARRAY_LEN(ary); if (len < k && n <= numberof(idx)) { for (i = 0; i < n; ++i) { if (rnds[i] >= len) return rb_ary_new_capa(0); } } if (n > len) n = len; switch (n) { case 0: return rb_ary_new_capa(0); case 1: i = rnds[0]; return rb_ary_new_from_values(1, &RARRAY_AREF(ary, i)); case 2: i = rnds[0]; j = rnds[1]; if (j >= i) j++; return rb_ary_new_from_args(2, RARRAY_AREF(ary, i), RARRAY_AREF(ary, j)); case 3: i = rnds[0]; j = rnds[1]; k = rnds[2]; { long l = j, g = i; if (j >= i) l = i, g = ++j; if (k >= l && (++k >= g)) ++k; } return rb_ary_new_from_args(3, RARRAY_AREF(ary, i), RARRAY_AREF(ary, j), RARRAY_AREF(ary, k)); } memo_threshold = len < 2560 ? len / 128 : len < 5120 ? len / 64 : len < 10240 ? len / 32 : len / 16; if (n <= numberof(idx)) { long sorted[numberof(idx)]; sorted[0] = idx[0] = rnds[0]; for (i=1; i max_idx) max_idx = r; } len = RARRAY_LEN(ary); if (len <= max_idx) n = 0; else if (n > len) n = len; RARRAY_PTR_USE(ary, ptr_ary, { for (i=0; i 0)) { n = RARRAY_AREF(args, 0); } if (RARRAY_LEN(self) == 0) return INT2FIX(0); if (n == Qnil) return DBL2NUM(INFINITY); mul = NUM2LONG(n); if (mul <= 0) return INT2FIX(0); n = LONG2FIX(mul); return rb_funcallv(rb_ary_length(self), '*', 1, &n); } /* * call-seq: * ary.cycle(n=nil) { |obj| block } -> nil * ary.cycle(n=nil) -> Enumerator * * Calls the given block for each element +n+ times or forever if +nil+ is * given. * * Does nothing if a non-positive number is given or the array is empty. * * Returns +nil+ if the loop has finished without getting interrupted. * * If no block is given, an Enumerator is returned instead. * * 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_SIZED_ENUMERATOR(ary, argc, argv, rb_ary_cycle_size); 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; iklass; } /* * Compute permutations of +r+ elements of the set [0..n-1]. * * When we have a complete permutation of array indices, copy the values * at those indices into a new array and yield that array. * * n: the size of the set * r: the number of elements in each permutation * p: the array (of size r) that we're filling in * used: an array of booleans: whether a given index is already used * values: the Ruby array that holds the actual values to permute */ static void permute0(const long n, const long r, long *const p, char *const used, const VALUE values) { long i = 0, index = 0; for (;;) { const char *const unused = memchr(&used[i], 0, n-i); if (!unused) { if (!index) break; i = p[--index]; /* pop index */ used[i++] = 0; /* index unused */ } else { i = unused - used; p[index] = i; used[i] = 1; /* mark index used */ ++index; if (index < r-1) { /* if not done yet */ p[index] = i = 0; continue; } for (i = 0; i < n; ++i) { if (used[i]) continue; p[index] = i; if (!yield_indexed_values(values, r, p)) { rb_raise(rb_eRuntimeError, "permute reentered"); } } i = p[--index]; /* pop index */ used[i] = 0; /* index unused */ p[index] = ++i; } } } /* * Returns the product of from, from-1, ..., from - how_many + 1. * http://en.wikipedia.org/wiki/Pochhammer_symbol */ static VALUE descending_factorial(long from, long how_many) { VALUE cnt = LONG2FIX(how_many >= 0); while (how_many-- > 0) { VALUE v = LONG2FIX(from--); cnt = rb_funcallv(cnt, '*', 1, &v); } return cnt; } static VALUE binomial_coefficient(long comb, long size) { VALUE r, v; if (comb > size-comb) { comb = size-comb; } if (comb < 0) { return LONG2FIX(0); } r = descending_factorial(size, comb); v = descending_factorial(comb, comb); return rb_funcallv(r, id_div, 1, &v); } static VALUE rb_ary_permutation_size(VALUE ary, VALUE args, VALUE eobj) { long n = RARRAY_LEN(ary); long k = (args && (RARRAY_LEN(args) > 0)) ? NUM2LONG(RARRAY_AREF(args, 0)) : n; return descending_factorial(n, k); } /* * call-seq: * ary.permutation { |p| block } -> ary * ary.permutation -> Enumerator * ary.permutation(n) { |p| block } -> ary * ary.permutation(n) -> Enumerator * * When invoked with a block, yield all permutations of length +n+ of the * elements of the array, 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. * * If no block is given, an Enumerator is returned 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_SIZED_ENUMERATOR(ary, argc, argv, rb_ary_permutation_size); /* 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_AREF(ary, i))); } } else { /* this is the general case */ volatile VALUE t0; long *p = ALLOCV_N(long, t0, r+roomof(n, sizeof(long))); char *used = (char*)(p + r); VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */ RBASIC_CLEAR_CLASS(ary0); MEMZERO(used, char, n); /* initialize array */ permute0(n, r, p, used, ary0); /* compute and yield permutations */ ALLOCV_END(t0); RBASIC_SET_CLASS_RAW(ary0, rb_cArray); } return ary; } static void combinate0(const long len, const long n, long *const stack, const VALUE values) { long lev = 0; MEMZERO(stack+1, long, n); stack[0] = -1; for (;;) { for (lev++; lev < n; lev++) { stack[lev+1] = stack[lev]+1; } if (!yield_indexed_values(values, n, stack+1)) { rb_raise(rb_eRuntimeError, "combination reentered"); } do { if (lev == 0) return; stack[lev--]++; } while (stack[lev+1]+n == len+lev+1); } } static VALUE rb_ary_combination_size(VALUE ary, VALUE args, VALUE eobj) { long n = RARRAY_LEN(ary); long k = NUM2LONG(RARRAY_AREF(args, 0)); return binomial_coefficient(k, n); } /* * 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 the array and then returns the array itself. * * The implementation makes no guarantees about the order in which the * combinations are yielded. * * If no block is given, an Enumerator is returned 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 i, n, len; n = NUM2LONG(num); RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_combination_size); 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 < RARRAY_LEN(ary); i++) { rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i))); } } else { VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */ volatile VALUE t0; long *stack = ALLOCV_N(long, t0, n+1); RBASIC_CLEAR_CLASS(ary0); combinate0(len, n, stack, ary0); ALLOCV_END(t0); RBASIC_SET_CLASS_RAW(ary0, rb_cArray); } return ary; } /* * Compute repeated permutations of +r+ elements of the set * [0..n-1]. * * When we have a complete repeated permutation of array indices, copy the * values at those indices into a new array and yield that array. * * n: the size of the set * r: the number of elements in each permutation * p: the array (of size r) that we're filling in * values: the Ruby array that holds the actual values to permute */ static void rpermute0(const long n, const long r, long *const p, const VALUE values) { long i = 0, index = 0; p[index] = i; for (;;) { if (++index < r-1) { p[index] = i = 0; continue; } for (i = 0; i < n; ++i) { p[index] = i; if (!yield_indexed_values(values, r, p)) { rb_raise(rb_eRuntimeError, "repeated permute reentered"); } } do { if (index <= 0) return; } while ((i = ++p[--index]) >= n); } } static VALUE rb_ary_repeated_permutation_size(VALUE ary, VALUE args, VALUE eobj) { long n = RARRAY_LEN(ary); long k = NUM2LONG(RARRAY_AREF(args, 0)); VALUE v; if (k < 0) { return LONG2FIX(0); } v = LONG2NUM(k); return rb_funcallv(LONG2NUM(n), idPow, 1, &v); } /* * call-seq: * ary.repeated_permutation(n) { |p| block } -> ary * ary.repeated_permutation(n) -> Enumerator * * When invoked with a block, yield all repeated permutations of length +n+ of * the elements of the array, then return the array itself. * * The implementation makes no guarantees about the order in which the repeated * permutations are yielded. * * If no block is given, an Enumerator is returned instead. * * Examples: * * a = [1, 2] * a.repeated_permutation(1).to_a #=> [[1], [2]] * a.repeated_permutation(2).to_a #=> [[1,1],[1,2],[2,1],[2,2]] * a.repeated_permutation(3).to_a #=> [[1,1,1],[1,1,2],[1,2,1],[1,2,2], * # [2,1,1],[2,1,2],[2,2,1],[2,2,2]] * a.repeated_permutation(0).to_a #=> [[]] # one permutation of length 0 */ static VALUE rb_ary_repeated_permutation(VALUE ary, VALUE num) { long r, n, i; n = RARRAY_LEN(ary); /* Array length */ RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_repeated_permutation_size); /* Return Enumerator if no block */ r = NUM2LONG(num); /* Permutation size from argument */ if (r < 0) { /* 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_AREF(ary, i))); } } else { /* this is the general case */ volatile VALUE t0; long *p = ALLOCV_N(long, t0, r); VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */ RBASIC_CLEAR_CLASS(ary0); rpermute0(n, r, p, ary0); /* compute and yield repeated permutations */ ALLOCV_END(t0); RBASIC_SET_CLASS_RAW(ary0, rb_cArray); } return ary; } static void rcombinate0(const long n, const long r, long *const p, const long rest, const VALUE values) { long i = 0, index = 0; p[index] = i; for (;;) { if (++index < r-1) { p[index] = i; continue; } for (; i < n; ++i) { p[index] = i; if (!yield_indexed_values(values, r, p)) { rb_raise(rb_eRuntimeError, "repeated combination reentered"); } } do { if (index <= 0) return; } while ((i = ++p[--index]) >= n); } } static VALUE rb_ary_repeated_combination_size(VALUE ary, VALUE args, VALUE eobj) { long n = RARRAY_LEN(ary); long k = NUM2LONG(RARRAY_AREF(args, 0)); if (k == 0) { return LONG2FIX(1); } return binomial_coefficient(k, n + k - 1); } /* * call-seq: * ary.repeated_combination(n) { |c| block } -> ary * ary.repeated_combination(n) -> Enumerator * * When invoked with a block, yields all repeated combinations of length +n+ of * elements from the array and then returns the array itself. * * The implementation makes no guarantees about the order in which the repeated * combinations are yielded. * * If no block is given, an Enumerator is returned instead. * * Examples: * * a = [1, 2, 3] * a.repeated_combination(1).to_a #=> [[1], [2], [3]] * a.repeated_combination(2).to_a #=> [[1,1],[1,2],[1,3],[2,2],[2,3],[3,3]] * a.repeated_combination(3).to_a #=> [[1,1,1],[1,1,2],[1,1,3],[1,2,2],[1,2,3], * # [1,3,3],[2,2,2],[2,2,3],[2,3,3],[3,3,3]] * a.repeated_combination(4).to_a #=> [[1,1,1,1],[1,1,1,2],[1,1,1,3],[1,1,2,2],[1,1,2,3], * # [1,1,3,3],[1,2,2,2],[1,2,2,3],[1,2,3,3],[1,3,3,3], * # [2,2,2,2],[2,2,2,3],[2,2,3,3],[2,3,3,3],[3,3,3,3]] * a.repeated_combination(0).to_a #=> [[]] # one combination of length 0 * */ static VALUE rb_ary_repeated_combination(VALUE ary, VALUE num) { long n, i, len; n = NUM2LONG(num); /* Combination size from argument */ RETURN_SIZED_ENUMERATOR(ary, 1, &num, rb_ary_repeated_combination_size); /* Return enumerator if no block */ len = RARRAY_LEN(ary); if (n < 0) { /* yield nothing */ } else if (n == 0) { rb_yield(rb_ary_new2(0)); } else if (n == 1) { for (i = 0; i < RARRAY_LEN(ary); i++) { rb_yield(rb_ary_new3(1, RARRAY_AREF(ary, i))); } } else if (len == 0) { /* yield nothing */ } else { volatile VALUE t0; long *p = ALLOCV_N(long, t0, n); VALUE ary0 = ary_make_shared_copy(ary); /* private defensive copy of ary */ RBASIC_CLEAR_CLASS(ary0); rcombinate0(len, n, p, n, ary0); /* compute and yield repeated combinations */ ALLOCV_END(t0); RBASIC_SET_CLASS_RAW(ary0, rb_cArray); } return ary; } /* * call-seq: * ary.product(other_ary, ...) -> new_ary * ary.product(other_ary, ...) { |p| block } -> 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 +self+ and * the argument arrays. * * If given a block, #product will yield all combinations and return +self+ * instead. * * [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 = tmpary(n); volatile VALUE t1 = tmpbuf(n, sizeof(int)); VALUE *arrays = RARRAY_PTR(t0); /* The arrays we're computing the product of */ int *counters = (int*)RSTRING_PTR(t1); /* The current position in each one */ VALUE result = Qnil; /* The array we'll be returning, when no block given */ long i,j; long resultlen = 1; RBASIC_CLEAR_CLASS(t0); RBASIC_CLEAR_CLASS(t1); /* initialize the arrays of arrays */ ARY_SET_LEN(t0, n); arrays[0] = ary; for (i = 1; i < n; i++) arrays[i] = Qnil; 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; /* Otherwise, allocate and fill in an array of results */ if (rb_block_given_p()) { /* Make defensive copies of arrays; exit if any is empty */ for (i = 0; i < n; i++) { if (RARRAY_LEN(arrays[i]) == 0) goto done; arrays[i] = ary_make_shared_copy(arrays[i]); } } else { /* Compute the length of the result array; return [] if any is empty */ for (i = 0; i < n; i++) { long k = RARRAY_LEN(arrays[i]); if (k == 0) { result = rb_ary_new2(0); goto done; } if (MUL_OVERFLOW_LONG_P(resultlen, k)) rb_raise(rb_eRangeError, "too big to product"); resultlen *= k; } result = rb_ary_new2(resultlen); } for (;;) { 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 */ if (NIL_P(result)) { FL_SET(t0, FL_USER5); rb_yield(subarray); if (! FL_TEST(t0, FL_USER5)) { rb_raise(rb_eRuntimeError, "product reentered"); } else { FL_UNSET(t0, FL_USER5); } } else { 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 (counters[m] == RARRAY_LEN(arrays[m])) { counters[m] = 0; /* If the first counter overflows, we are done */ if (--m < 0) goto done; counters[m]++; } } done: tmpary_discard(t0); tmpbuf_discard(t1); return NIL_P(result) ? ary : result; } /* * call-seq: * ary.take(n) -> new_ary * * Returns first +n+ elements from the array. * * If a negative number is given, raises an ArgumentError. * * See also Array#drop * * 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 { |obj| block } -> new_ary * ary.take_while -> Enumerator * * Passes elements to the block until the block returns +nil+ or +false+, then * stops iterating and returns an array of all prior elements. * * If no block is given, an Enumerator is returned instead. * * See also Array#drop_while * * 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_AREF(ary, i)))) break; } return rb_ary_take(ary, LONG2FIX(i)); } /* * call-seq: * ary.drop(n) -> new_ary * * Drops first +n+ elements from +ary+ and returns the rest of the elements in * an array. * * If a negative number is given, raises an ArgumentError. * * See also Array#take * * 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 { |obj| block } -> new_ary * ary.drop_while -> Enumerator * * 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. * * If no block is given, an Enumerator is returned instead. * * See also Array#take_while * * 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_AREF(ary, i)))) break; } return rb_ary_drop(ary, LONG2FIX(i)); } /* * call-seq: * ary.any? [{ |obj| block }] -> true or false * * See also Enumerable#any? */ static VALUE rb_ary_any_p(VALUE ary) { long i, len = RARRAY_LEN(ary); const VALUE *ptr = RARRAY_CONST_PTR(ary); if (!len) return Qfalse; if (!rb_block_given_p()) { for (i = 0; i < len; ++i) if (RTEST(ptr[i])) return Qtrue; } else { for (i = 0; i < RARRAY_LEN(ary); ++i) { if (RTEST(rb_yield(RARRAY_AREF(ary, i)))) return Qtrue; } } return Qfalse; } /* * call-seq: * ary.dig(idx, ...) -> object * * Extracts the nested value specified by the sequence of idx * objects by calling +dig+ at each step, returning +nil+ if any * intermediate step is +nil+. * * a = [[1, [2, 3]]] * * a.dig(0, 1, 1) #=> 3 * a.dig(1, 2, 3) #=> nil * a.dig(0, 0, 0) #=> TypeError: Integer does not have #dig method * [42, {foo: :bar}].dig(1, :foo) #=> :bar */ VALUE rb_ary_dig(int argc, VALUE *argv, VALUE self) { rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); self = rb_ary_at(self, *argv); if (!--argc) return self; ++argv; return rb_obj_dig(argc, argv, self, Qnil); } static inline VALUE finish_exact_sum(long n, VALUE r, VALUE v, int z) { if (n != 0) v = rb_fix_plus(LONG2FIX(n), v); if (r != Qundef) { /* r can be an Integer when mathn is loaded */ if (FIXNUM_P(r)) v = rb_fix_plus(r, v); else if (RB_TYPE_P(r, T_BIGNUM)) v = rb_big_plus(r, v); else v = rb_rational_plus(r, v); } else if (!n && z) { v = rb_fix_plus(LONG2FIX(0), v); } return v; } /* * call-seq: * ary.sum(init=0) -> number * ary.sum(init=0) {|e| expr } -> number * * Returns the sum of elements. * For example, [e1, e2, e3].sum returns init + e1 + e2 + e3. * * If a block is given, the block is applied to each element * before addition. * * If ary is empty, it returns init. * * [].sum #=> 0 * [].sum(0.0) #=> 0.0 * [1, 2, 3].sum #=> 6 * [3, 5.5].sum #=> 8.5 * [2.5, 3.0].sum(0.0) {|e| e * e } #=> 15.25 * [Object.new].sum #=> TypeError * * The (arithmetic) mean value of an array can be obtained as follows. * * mean = ary.sum(0.0) / ary.length * * This method can be used for non-numeric objects by * explicit init argument. * * ["a", "b", "c"].sum("") #=> "abc" * [[1], [[2]], [3]].sum([]) #=> [1, [2], 3] * * However, Array#join and Array#flatten is faster than Array#sum for * array of strings and array of arrays. * * ["a", "b", "c"].join #=> "abc" * [[1], [[2]], [3]].flatten(1) #=> [1, [2], 3] * * * Array#sum method may not respect method redefinition of "+" methods * such as Integer#+. * */ static VALUE rb_ary_sum(int argc, VALUE *argv, VALUE ary) { VALUE e, v, r; long i, n; int block_given; if (rb_scan_args(argc, argv, "01", &v) == 0) v = LONG2FIX(0); block_given = rb_block_given_p(); if (RARRAY_LEN(ary) == 0) return v; n = 0; r = Qundef; for (i = 0; i < RARRAY_LEN(ary); i++) { e = RARRAY_AREF(ary, i); if (block_given) e = rb_yield(e); if (FIXNUM_P(e)) { n += FIX2LONG(e); /* should not overflow long type */ if (!FIXABLE(n)) { v = rb_big_plus(LONG2NUM(n), v); n = 0; } } else if (RB_TYPE_P(e, T_BIGNUM)) v = rb_big_plus(e, v); else if (RB_TYPE_P(e, T_RATIONAL)) { if (r == Qundef) r = e; else r = rb_rational_plus(r, e); } else goto not_exact; } v = finish_exact_sum(n, r, v, argc!=0); return v; not_exact: v = finish_exact_sum(n, r, v, i!=0); if (RB_FLOAT_TYPE_P(e)) { /* * Kahan-Babuska balancing compensated summation algorithm * See http://link.springer.com/article/10.1007/s00607-005-0139-x */ double f, c; f = NUM2DBL(v); c = 0.0; goto has_float_value; for (; i < RARRAY_LEN(ary); i++) { double x, t; e = RARRAY_AREF(ary, i); if (block_given) e = rb_yield(e); if (RB_FLOAT_TYPE_P(e)) has_float_value: x = RFLOAT_VALUE(e); else if (FIXNUM_P(e)) x = FIX2LONG(e); else if (RB_TYPE_P(e, T_BIGNUM)) x = rb_big2dbl(e); else if (RB_TYPE_P(e, T_RATIONAL)) x = rb_num2dbl(e); else goto not_float; t = f + x; if (fabs(f) >= fabs(x)) c += ((f - t) + x); else c += ((x - t) + f); f = t; } f += c; return DBL2NUM(f); not_float: v = DBL2NUM(f); } goto has_some_value; for (; i < RARRAY_LEN(ary); i++) { e = RARRAY_AREF(ary, i); if (block_given) e = rb_yield(e); has_some_value: v = rb_funcall(v, idPLUS, 1, e); } return v; } /* * 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. * * == Creating Arrays * * A new array can be created by using the literal constructor * []. Arrays can contain different types of objects. For * example, the array below contains an Integer, a String and a Float: * * ary = [1, "two", 3.0] #=> [1, "two", 3.0] * * An array can also be created by explicitly calling Array.new with zero, one * (the initial size of the Array) or two arguments (the initial size and a * default object). * * ary = Array.new #=> [] * Array.new(3) #=> [nil, nil, nil] * Array.new(3, true) #=> [true, true, true] * * Note that the second argument populates the array with references to the * same object. Therefore, it is only recommended in cases when you need to * instantiate arrays with natively immutable objects such as Symbols, * numbers, true or false. * * To create an array with separate objects a block can be passed instead. * This method is safe to use with mutable objects such as hashes, strings or * other arrays: * * Array.new(4) { Hash.new } #=> [{}, {}, {}, {}] * Array.new(4) {|i| i.to_s } #=> ["0", "1", "2", "3"] * * This is also a quick way to build up multi-dimensional arrays: * * empty_table = Array.new(3) { Array.new(3) } * #=> [[nil, nil, nil], [nil, nil, nil], [nil, nil, nil]] * * An array can also be created by using the Array() method, provided by * Kernel, which tries to call #to_ary, then #to_a on its argument. * * Array({:a => "a", :b => "b"}) #=> [[:a, "a"], [:b, "b"]] * * == Example Usage * * In addition to the methods it mixes in through the Enumerable module, the * Array class has proprietary methods for accessing, searching and otherwise * manipulating arrays. * * Some of the more common ones are illustrated below. * * == Accessing Elements * * Elements in an array can be retrieved using the Array#[] method. It can * take a single integer argument (a numeric index), a pair of arguments * (start and length) or a range. Negative indices start counting from the end, * with -1 being the last element. * * arr = [1, 2, 3, 4, 5, 6] * arr[2] #=> 3 * arr[100] #=> nil * arr[-3] #=> 4 * arr[2, 3] #=> [3, 4, 5] * arr[1..4] #=> [2, 3, 4, 5] * arr[1..-3] #=> [2, 3, 4] * * Another way to access a particular array element is by using the #at method * * arr.at(0) #=> 1 * * The #slice method works in an identical manner to Array#[]. * * To raise an error for indices outside of the array bounds or else to * provide a default value when that happens, you can use #fetch. * * arr = ['a', 'b', 'c', 'd', 'e', 'f'] * arr.fetch(100) #=> IndexError: index 100 outside of array bounds: -6...6 * arr.fetch(100, "oops") #=> "oops" * * The special methods #first and #last will return the first and last * elements of an array, respectively. * * arr.first #=> 1 * arr.last #=> 6 * * To return the first +n+ elements of an array, use #take * * arr.take(3) #=> [1, 2, 3] * * #drop does the opposite of #take, by returning the elements after +n+ * elements have been dropped: * * arr.drop(3) #=> [4, 5, 6] * * == Obtaining Information about an Array * * Arrays keep track of their own length at all times. To query an array * about the number of elements it contains, use #length, #count or #size. * * browsers = ['Chrome', 'Firefox', 'Safari', 'Opera', 'IE'] * browsers.length #=> 5 * browsers.count #=> 5 * * To check whether an array contains any elements at all * * browsers.empty? #=> false * * To check whether a particular item is included in the array * * browsers.include?('Konqueror') #=> false * * == Adding Items to Arrays * * Items can be added to the end of an array by using either #push or #<< * * arr = [1, 2, 3, 4] * arr.push(5) #=> [1, 2, 3, 4, 5] * arr << 6 #=> [1, 2, 3, 4, 5, 6] * * #unshift will add a new item to the beginning of an array. * * arr.unshift(0) #=> [0, 1, 2, 3, 4, 5, 6] * * With #insert you can add a new element to an array at any position. * * arr.insert(3, 'apple') #=> [0, 1, 2, 'apple', 3, 4, 5, 6] * * Using the #insert method, you can also insert multiple values at once: * * arr.insert(3, 'orange', 'pear', 'grapefruit') * #=> [0, 1, 2, "orange", "pear", "grapefruit", "apple", 3, 4, 5, 6] * * == Removing Items from an Array * * The method #pop removes the last element in an array and returns it: * * arr = [1, 2, 3, 4, 5, 6] * arr.pop #=> 6 * arr #=> [1, 2, 3, 4, 5] * * To retrieve and at the same time remove the first item, use #shift: * * arr.shift #=> 1 * arr #=> [2, 3, 4, 5] * * To delete an element at a particular index: * * arr.delete_at(2) #=> 4 * arr #=> [2, 3, 5] * * To delete a particular element anywhere in an array, use #delete: * * arr = [1, 2, 2, 3] * arr.delete(2) #=> 2 * arr #=> [1,3] * * A useful method if you need to remove +nil+ values from an array is * #compact: * * arr = ['foo', 0, nil, 'bar', 7, 'baz', nil] * arr.compact #=> ['foo', 0, 'bar', 7, 'baz'] * arr #=> ['foo', 0, nil, 'bar', 7, 'baz', nil] * arr.compact! #=> ['foo', 0, 'bar', 7, 'baz'] * arr #=> ['foo', 0, 'bar', 7, 'baz'] * * Another common need is to remove duplicate elements from an array. * * It has the non-destructive #uniq, and destructive method #uniq! * * arr = [2, 5, 6, 556, 6, 6, 8, 9, 0, 123, 556] * arr.uniq #=> [2, 5, 6, 556, 8, 9, 0, 123] * * == Iterating over Arrays * * Like all classes that include the Enumerable module, Array has an each * method, which defines what elements should be iterated over and how. In * case of Array's #each, all elements in the Array instance are yielded to * the supplied block in sequence. * * Note that this operation leaves the array unchanged. * * arr = [1, 2, 3, 4, 5] * arr.each { |a| print a -= 10, " " } * # prints: -9 -8 -7 -6 -5 * #=> [1, 2, 3, 4, 5] * * Another sometimes useful iterator is #reverse_each which will iterate over * the elements in the array in reverse order. * * words = %w[first second third fourth fifth sixth] * str = "" * words.reverse_each { |word| str += "#{word} " } * p str #=> "sixth fifth fourth third second first " * * The #map method can be used to create a new array based on the original * array, but with the values modified by the supplied block: * * arr.map { |a| 2*a } #=> [2, 4, 6, 8, 10] * arr #=> [1, 2, 3, 4, 5] * arr.map! { |a| a**2 } #=> [1, 4, 9, 16, 25] * arr #=> [1, 4, 9, 16, 25] * * == Selecting Items from an Array * * Elements can be selected from an array according to criteria defined in a * block. The selection can happen in a destructive or a non-destructive * manner. While the destructive operations will modify the array they were * called on, the non-destructive methods usually return a new array with the * selected elements, but leave the original array unchanged. * * === Non-destructive Selection * * arr = [1, 2, 3, 4, 5, 6] * arr.select { |a| a > 3 } #=> [4, 5, 6] * arr.reject { |a| a < 3 } #=> [3, 4, 5, 6] * arr.drop_while { |a| a < 4 } #=> [4, 5, 6] * arr #=> [1, 2, 3, 4, 5, 6] * * === Destructive Selection * * #select! and #reject! are the corresponding destructive methods to #select * and #reject * * Similar to #select vs. #reject, #delete_if and #keep_if have the exact * opposite result when supplied with the same block: * * arr.delete_if { |a| a < 4 } #=> [4, 5, 6] * arr #=> [4, 5, 6] * * arr = [1, 2, 3, 4, 5, 6] * arr.keep_if { |a| a < 4 } #=> [1, 2, 3] * arr #=> [1, 2, 3] * */ 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, empty_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, "inspect", rb_ary_inspect, 0); rb_define_alias(rb_cArray, "to_s", "inspect"); rb_define_method(rb_cArray, "to_a", rb_ary_to_a, 0); rb_define_method(rb_cArray, "to_h", rb_ary_to_h, 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_multi, -1); rb_define_method(rb_cArray, "<<", rb_ary_push, 1); rb_define_method(rb_cArray, "push", rb_ary_push_m, -1); rb_define_alias(rb_cArray, "append", "push"); 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_alias(rb_cArray, "prepend", "unshift"); 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, "rotate", rb_ary_rotate_m, -1); rb_define_method(rb_cArray, "rotate!", rb_ary_rotate_bang, -1); 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, "sort_by!", rb_ary_sort_by_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, "select!", rb_ary_select_bang, 0); rb_define_method(rb_cArray, "keep_if", rb_ary_keep_if, 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, "max", rb_ary_max, -1); rb_define_method(rb_cArray, "min", rb_ary_min, -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, -1); rb_define_method(rb_cArray, "shuffle", rb_ary_shuffle, -1); 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, "repeated_permutation", rb_ary_repeated_permutation, 1); rb_define_method(rb_cArray, "repeated_combination", rb_ary_repeated_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); rb_define_method(rb_cArray, "bsearch", rb_ary_bsearch, 0); rb_define_method(rb_cArray, "bsearch_index", rb_ary_bsearch_index, 0); rb_define_method(rb_cArray, "any?", rb_ary_any_p, 0); rb_define_method(rb_cArray, "dig", rb_ary_dig, -1); rb_define_method(rb_cArray, "sum", rb_ary_sum, -1); id_random = rb_intern("random"); id_div = rb_intern("div"); } yard-0.9.12/spec/parser/examples/override.c.txt0000755000004100000410000002511113206751010021435 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.9.12/spec/parser/examples/parse_in_order_002.rb.txt0000755000004100000410000000002313206751010023346 0ustar www-datawww-datamodule MyModule endyard-0.9.12/spec/parser/examples/namespace.cpp.txt0000755000004100000410000000272213206751010022115 0ustar www-datawww-dataVALUE rb_cWXRect; namespace RubyWX { namespace Rect { VALUE _alloc(VALUE self) { return wrap(new wxRect()); } /* * call-seq: * inspect -> String * * Human-readable description. * ===Return value * String */ VALUE _inspect(VALUE self) { return rb_sprintf( "%s(%d, %d, %d, %d)", rb_obj_classname( self ), FIX2INT(_getX(self)), FIX2INT(_getY(self)), FIX2INT(_getWidth(self)), FIX2INT(_getHeight(self))); } } // namespace Rect } // namespace RubyWX /* * call-seq: * hello_world -> String * * Human-readable description. * ===Return value * String */ VALUE _hello_world(VALUE self) { return rb_sprintf( "%s(%d, %d, %d, %d)", rb_obj_classname( self ), FIX2INT(_getX(self)), FIX2INT(_getY(self)), FIX2INT(_getWidth(self)), FIX2INT(_getHeight(self))); } /* 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_Rect() { using namespace RubyWX::Rect; rb_cWXRect = rb_define_class("Rect",rb_cObject); rb_define_alloc_func(rb_cWXRect,_alloc); rb_define_method(rb_cWXRect,"inspect",RUBY_METHOD_FUNC(_inspect),0); rb_define_method(rb_cWXRect,"hello_world",RUBY_METHOD_FUNC(_hello_world),0); } yard-0.9.12/spec/parser/tag_parsing_spec.rb0000755000004100000410000000073013206751010020653 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::Parser, "tag handling" do before { parse_file :tag_handler_001, __FILE__ } it "knows the list of all available tags" do expect(P("Foo#foo").tags).to include(P("Foo#foo").tag(:api)) end it "knows the text of tags on a method" do expect(P("Foo#foo").tag(:api).text).to eq "public" end it "returns true when asked whether a tag exists" do expect(P("Foo#foo").has_tag?(:api)).to be true end end yard-0.9.12/spec/parser/source_parser_spec.rb0000755000004100000410000006067113206751010021243 0ustar www-datawww-data# frozen_string_literal: true class MyParser < Parser::Base; end RSpec.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 RSpec.describe YARD::Parser::SourceParser do before do Registry.clear end def parse_list(*list) files = list.map do |v| filename, source = *v allow(File).to receive(: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 "handles basic callback support" do before_list do |files, globals| expect(files).to eq ['foo.rb', 'bar.rb'] expect(globals).to eq OpenStruct.new end parse_list ['foo.rb', 'foo!'], ['bar.rb', 'class Foo; end'] expect(Registry.at('Foo')).not_to be nil end it "supports multiple callbacks" do checks = [] before_list { checks << :one } before_list { checks << :two } parse_list ['file.rb', ''], ['file2.rb', ''], ['file3.rb', 'class Foo; end'] expect(Registry.at('Foo')).not_to be nil expect(checks).to eq [:one, :two] end it "cancels 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'] expect(Registry.at('Foo')).to be nil expect(checks).to eq [:one] end it "does 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'] expect(Registry.at('Foo')).not_to be nil expect(checks).to eq [:one, :two] end it "passes 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| expect(g.x).to eq 3 } parse_list ['file.rb', ''], ['file2.rb', ''], ['file3.rb', 'class Foo; end'] expect(Registry.at('Foo')).not_to 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 "handles basic callback support and maintain files/globals" do before_list {|_f, g| g.foo = :bar } after_list do |files, globals| expect(files).to eq ['foo.rb', 'bar.rb'] expect(globals.foo).to eq :bar end parse_list ['foo.rb', 'foo!'], ['bar.rb', 'class Foo; end'] expect(Registry.at('Foo')).not_to be nil end it "supports multiple callbacks" do checks = [] after_list { checks << :one } after_list { checks << :two } parse_list ['file.rb', ''], ['file2.rb', ''], ['file3.rb', 'class Foo; end'] expect(Registry.at('Foo')).not_to be nil expect(checks).to eq [:one, :two] end it "does 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'] expect(Registry.at('Foo')).not_to be nil expect(checks).to eq [: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 "handles basic callback support" do before_file do |parser| expect(parser.contents).to eq 'class Foo; end' expect(parser.file).to match(/(foo|bar)\.rb/) end parse_list ['foo.rb', 'class Foo; end'], ['bar.rb', 'class Foo; end'] expect(Registry.at('Foo')).not_to be nil end it "supports multiple callbacks" do checks = [] before_file { checks << :one } before_file { checks << :two } parse_list ['file.rb', ''], ['file2.rb', ''], ['file3.rb', 'class Foo; end'] expect(Registry.at('Foo')).not_to be nil expect(checks).to eq [:one, :two, :one, :two, :one, :two] end it "cancels 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'] expect(Registry.at('Foo')).to be nil expect(checks).to eq [:one, :one, :one] end it "does 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'] expect(Registry.at('Foo')).not_to be nil expect(checks).to eq [: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 "handles basic callback support" do after_file do |parser| expect(parser.contents).to eq 'class Foo; end' expect(parser.file).to match(/(foo|bar)\.rb/) end parse_list ['foo.rb', 'class Foo; end'], ['bar.rb', 'class Foo; end'] expect(Registry.at('Foo')).not_to be nil end it "supports multiple callbacks" do checks = [] after_file { checks << :one } after_file { checks << :two } parse_list ['file.rb', ''], ['file2.rb', ''], ['file3.rb', 'class Foo; end'] expect(Registry.at('Foo')).not_to be nil expect(checks).to eq [:one, :two, :one, :two, :one, :two] end it "does 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'] expect(Registry.at('Foo')).not_to be nil expect(checks).to eq [:one, :three, :one, :three, :one, :three] end end describe ".register_parser_type" do it_should_behave_like "parser type registration" it "registers a subclass of Parser::Base" do parser = double(:parser) expect(parser).to receive(:parse) expect(MyParser).to 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 "requires class to be a subclass of Parser::Base" do expect { Parser::SourceParser.register_parser_type(:my_parser, String) }.to raise_error(ArgumentError) expect { Parser::SourceParser.register_parser_type(:my_parser, Parser::Base) }.to raise_error(ArgumentError) end end describe ".parser_type_for_extension" do it_should_behave_like "parser type registration" it "finds an extension in a registered array of extensions" do Parser::SourceParser.register_parser_type(:my_parser, MyParser, ['a', 'b', 'd']) expect(Parser::SourceParser.parser_type_for_extension('a')).to eq :my_parser expect(Parser::SourceParser.parser_type_for_extension('b')).to eq :my_parser expect(Parser::SourceParser.parser_type_for_extension('d')).to eq :my_parser expect(Parser::SourceParser.parser_type_for_extension('c')).not_to eq :my_parser end it "finds an extension in a Regexp" do Parser::SourceParser.register_parser_type(:my_parser, MyParser, /abc$/) expect(Parser::SourceParser.parser_type_for_extension('dabc')).to eq :my_parser expect(Parser::SourceParser.parser_type_for_extension('dabcd')).not_to eq :my_parser end it "finds an extension in a list of Regexps" do Parser::SourceParser.register_parser_type(:my_parser, MyParser, [/ab$/, /abc$/]) expect(Parser::SourceParser.parser_type_for_extension('dabc')).to eq :my_parser expect(Parser::SourceParser.parser_type_for_extension('dabcd')).not_to eq :my_parser end it "finds an extension in a String" do Parser::SourceParser.register_parser_type(:my_parser, MyParser, "abc") expect(Parser::SourceParser.parser_type_for_extension('abc')).to eq :my_parser expect(Parser::SourceParser.parser_type_for_extension('abcd')).not_to eq :my_parser end end describe "#parse_string" do it "parses basic Ruby code" do YARD.parse_string(<<-eof) module Hello class Hi # Docstring # Docstring2 def me; "VALUE" end end end eof expect(Registry.at(:Hello)).not_to eq nil expect(Registry.at("Hello::Hi#me")).not_to eq nil expect(Registry.at("Hello::Hi#me").docstring).to eq "Docstring\nDocstring2" expect(Registry.at("Hello::Hi#me").docstring.line_range).to eq(3..4) end it "parses 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" expect(Registry.at(:Foo).docstring.hash_flag).to eq expected end end it "removes shebang from initial file comments" do YARD.parse_string "#!/bin/ruby\n# this is a comment\nclass Foo; end" expect(Registry.at(:Foo).docstring).to eq "this is a comment" end it "removes encoding line from initial file comments" do YARD.parse_string "# encoding: utf-8\n# this is a comment\nclass Foo; end" expect(Registry.at(:Foo).docstring).to eq "this is a comment" end it "adds 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') expect(macro.macro_data).to eq "This is a macro\n@return [String] the string" expect(Registry.at('Foo').docstring.to_raw).to eq macro.macro_data expect(Registry.at('Foo#foo').docstring.to_raw).to eq macro.macro_data end it "allows 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') expect(foo).not_to be nil expect(foo.visibility).to eq :private expect(foo.tag(:param).name).to eq 'a' expect(foo.tag(:return).types).to eq ['Symbol'] expect(bar).not_to be nil expect(bar.signature).to eq 'def bar(value)' end it "parses 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') expect(foo).not_to be nil expect(foo.signature).to eq 'def foo(a = "hello")' end it "handles lone comment with no code" do YARD.parse_string '# @!method foo(a = "hello")' foo = Registry.at('#foo') expect(foo).not_to be nil expect(foo.signature).to eq 'def foo(a = "hello")' end it "handles 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 expect(Registry.at('Foo').superclass).to eq P('Bar') end end describe "#parse" do it "parses a basic Ruby file" do parse_file :example1, __FILE__ expect(Registry.at(:Hello)).not_to eq nil expect(Registry.at("Hello::Hi#me")).not_to eq nil expect(Registry.at("Hello::Hi#me").docstring).to eq "Docstring" end it "parses a set of file globs" do expect(Dir).to receive(:[]).with('lib/**/*.rb').and_return([]) YARD.parse('lib/**/*.rb') end it "parses a set of absolute paths" do expect(Dir).not_to receive(:[]) expect(File).to receive(:file?).with('/path/to/file').and_return(true) expect(File).to receive(:read_binary).with('/path/to/file').and_return("") YARD.parse('/path/to/file') end it "cleans paths before parsing" do expect(File).to receive(:open).and_return("") parser = Parser::SourceParser.new(:ruby, true) parser.parse('a//b//c') expect(parser.file).to eq 'a/b/c' end it "parses files with '*' in them as globs and others as absolute paths" do expect(Dir).to receive(:[]).with('*.rb').and_return(['a.rb', 'b.rb']) expect(File).to receive(:file?).with('/path/to/file').and_return(true) expect(File).to receive(:file?).with('a.rb').and_return(true) expect(File).to receive(:file?).with('b.rb').and_return(true) expect(File).to receive(:read_binary).with('/path/to/file').and_return("") expect(File).to receive(:read_binary).with('a.rb').and_return("") expect(File).to receive(:read_binary).with('b.rb').and_return("") YARD.parse ['/path/to/file', '*.rb'] end it "converts directories into globs" do expect(Dir).to receive(:[]).with('foo/**/*.{rb,c,cc,cxx,cpp}').and_return(['foo/a.rb', 'foo/bar/b.rb']) expect(File).to receive(:directory?).with('foo').and_return(true) expect(File).to receive(:file?).with('foo/a.rb').and_return(true) expect(File).to receive(:file?).with('foo/bar/b.rb').and_return(true) expect(File).to receive(:read_binary).with('foo/a.rb').and_return("") expect(File).to receive(:read_binary).with('foo/bar/b.rb').and_return("") YARD.parse ['foo'] end it "uses Registry.checksums cache if file is cached" do data = 'DATA' hash = Registry.checksum_for(data) cmock = double(:cmock) expect(cmock).to receive(:[]).with('foo/bar').and_return(hash) expect(Registry).to receive(:checksums).and_return(cmock) expect(File).to receive(:file?).with('foo/bar').and_return(true) expect(File).to receive(:read_binary).with('foo/bar').and_return(data) YARD.parse('foo/bar') end it "supports excluded paths" do expect(File).to receive(:file?).with('foo/bar').and_return(true) expect(File).to receive(:file?).with('foo/baz').and_return(true) expect(File).not_to receive(:read_binary) YARD.parse(["foo/bar", "foo/baz"], ["foo", /baz$/]) end it "converts 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" {:to => valid, :not_to => invalid}.each do |msg, list| list.each do |src| Registry.clear parser = Parser::SourceParser.new expect(File).to receive(:read_binary).with('tmpfile').and_return(src) result = parser.parse("tmpfile") if HAVE_RIPPER && YARD.ruby19? if msg == :not_to default_encoding = 'UTF-8' expect(result.enumerator[0].source.encoding.to_s).to eq(default_encoding) else expect(['Shift_JIS', 'Windows-31J', 'UTF-8']).send(msg, include(result.enumerator[0].source.encoding.to_s)) end end expect(result.encoding_line).send(msg, eq(src.split("\n").last)) end end end it "converts 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 = [] {:to => valid, :not_to => invalid}.each do |msg, list| list.each do |src| Registry.clear parser = Parser::SourceParser.new expect(File).to receive(:read_binary).with('tmpfile.c').and_return(src) result = parser.parse("tmpfile.c") content = result.instance_variable_get("@content") expect(['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 "understands #{encoding.upcase} BOM" do parser = Parser::SourceParser.new src = bom + String.new("class FooBar; end").force_encoding('binary') src.force_encoding('binary') expect(File).to receive(:read_binary).with('tmpfile').and_return(src) result = parser.parse('tmpfile') expect(Registry.all(:class).first.path).to eq "FooBar" expect(result.enumerator[0].source.encoding.to_s.downcase).to eq 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 "attempts to parse files in order" do log.enter_level(Logger::DEBUG) do msgs = [] expect(log).to receive(:debug) {|m| msgs << m }.at_least(:once) allow(log).to receive(:<<) in_order_parse 'parse_in_order_001', 'parse_in_order_002' expect(msgs[1]).to match(/Parsing .+parse_in_order_001.+/) expect(msgs[2]).to match(/Missing object MyModule/) expect(msgs[3]).to match(/Parsing .+parse_in_order_002.+/) expect(msgs[4]).to match(/Re-processing .+parse_in_order_001.+/) end end it "attempts to order files by length for globs (process toplevel files first)" do files = %w(a a/b a/b/c) files.each do |file| expect(File).to receive(:file?).with(file).and_return(true) expect(File).to receive(:read_binary).with(file).ordered.and_return('') end expect(Dir).to receive(:[]).with('a/**/*').and_return(files.reverse) YARD.parse 'a/**/*' end it "allows overriding of length sorting when single file is presented" do files = %w(a/b/c a a/b) files.each do |file| expect(File).to receive(:file?).with(file).at_least(1).times.and_return(true) expect(File).to receive(:read_binary).with(file).ordered.and_return('') end expect(Dir).to 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 "displays a warning for invalid parser type" do expect(log).to receive(:warn).with(/unrecognized file/) expect(log).to receive(:backtrace) YARD::Parser::SourceParser.parse_string("int main() { }", :d) end if HAVE_RIPPER it "displays a warning for a syntax error (with new parser)" do expect(log).to receive(:warn).with(/Syntax error in/) expect(log).to receive(:backtrace) YARD::Parser::SourceParser.parse_string("%!!!", :ruby) end end it "handles 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 expect(Registry.at('A').groups).to eq ['Group Name', 'Group 2'] expect(Registry.at('A#bar').group).to be nil expect(Registry.at('A#foo').group).to eq "Group Name" expect(Registry.at('A#foo2').group).to eq "Group Name" expect(Registry.at('A#baz').group).to eq "Group 2" end it "handles multi-line class/module references" do YARD.parse_string <<-eof class A:: B::C; end eof expect(Registry.all).to eq [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 expect(Registry.all.size).to eq 2 expect(Registry.at('A::B::C')).not_to be nil expect(Registry.at('A::B::C.foo')).not_to 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 expect(Registry.at('A#d')).to be nil expect(Registry.at('A::B#d')).not_to be nil end if YARD.ruby2? it "supports named arguments with default values" do YARD.parse_string 'def foo(a, b = 1, *c, d, e: 3, **f, &g) end' args = [['a', nil], ['b', '1'], ['*c', nil], ['d', nil], ['e:', '3'], ['**f', nil], ['&g', nil]] expect(Registry.at('#foo').parameters).to eq(args) end end if NAMED_OPTIONAL_ARGUMENTS && !LEGACY_PARSER it "supports named arguments without default values" do YARD.parse_string 'def foo(a, b = 1, *c, d, e: 3, f:, **g, &h) end' args = [['a', nil], ['b', '1'], ['*c', nil], ['d', nil], ['e:', '3'], ['f:', nil], ['**g', nil], ['&h', nil]] expect(Registry.at('#foo').parameters).to eq(args) end end end end yard-0.9.12/spec/parser/c_parser_spec.rb0000755000004100000410000001562013206751010020157 0ustar www-datawww-data# frozen_string_literal: true RSpec.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 "parses Array class" do obj = YARD::Registry.at('Array') expect(obj).not_to be nil expect(obj.docstring).not_to be_blank end it "parses method" do obj = YARD::Registry.at('Array#initialize') expect(obj.docstring).not_to be_blank expect(obj.tags(:overload).size).to be > 1 end it "parses new_ary return type" do obj = YARD::Registry.at('Array#map') expect(obj.tags(:overload).count do |overload| overload.tag(:return) && overload.tag(:return).types == ['Enumerator'] end).to eq 2 expect(obj.tags(:overload).count do |overload| overload.tag(:return) && overload.tag(:return).types == ['Array'] end).to eq 2 end end describe "C++ namespace" do before(:all) do file = File.join(File.dirname(__FILE__), 'examples', 'namespace.cpp.txt') parse(File.read(file)) end it "parses Rect class" do obj = YARD::Registry.at('Rect') expect(obj).not_to be nil expect(obj.docstring).not_to be_blank end it "parses method inside of namespace" do obj = YARD::Registry.at('Rect#inspect') expect(obj.docstring).not_to be_blank end it "parses method after namespace" do obj = YARD::Registry.at('Rect#hello_world') expect(obj.docstring).not_to be_blank 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 "looks for methods in extra files (if 'in' comment is found)" do extra_contents = File.read(@extrafile) expect(File).to receive(:read).with('extra.c').and_return(extra_contents) parse(@contents) expect(Registry.at('Multifile#extra').docstring).to eq 'foo' end it "stops searching for extra source file gracefully if file is not found" do expect(File).to receive(:read).with('extra.c').and_raise(Errno::ENOENT) expect(log).to receive(:warn).with("Missing source file `extra.c' when parsing Multifile#extra") parse(@contents) expect(Registry.at('Multifile#extra').docstring).to eq '' end it "differentiates between a struct and a pointer to a struct retval" do parse(@contents) expect(Registry.at('Multifile#hello_mars').docstring).to eq 'Hello Mars' end end describe "Foo class" do it "does 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 expect(Registry.at('Foo#foo').source.gsub(/\s\s+/, ' ')).to eq( "VALUE foo(VALUE x) { int value = x;\n}" ) end end describe "Constant" do it "does 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') expect(constant.value).to eq '0xdeadbeef' expect(constant.docstring).to eq "This constant is frequently used to indicate a\nsoftware crash or deadlock in embedded systems." end end describe "Macros" do it "handles 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? thr.kill raise "Did not parse in time" end end end describe "C macros in declaration" do it "handles C macros in method declaration" do Registry.clear parse <<-eof // docstring FOOBAR VALUE func() { } void Init_mod(void) { rb_define_method(rb_cFoo, "func", func, 0); \ } eof expect(Registry.at('Foo#func').docstring).to eq "docstring" 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 "parses GMP::Z class" do z = YARD::Registry.at('GMP::Z') expect(z).not_to be nil expect(z.docstring).not_to be_blank end it "parses GMP::Z methods w/ bodies" do add = YARD::Registry.at('GMP::Z#+') expect(add.docstring).not_to be_blank expect(add.source).not_to be nil expect(add.source).not_to be_empty add_self = YARD::Registry.at('GMP::Z#+') expect(add_self.docstring).not_to be_blank expect(add_self.source).not_to be nil expect(add_self.source).not_to be_empty sqrtrem = YARD::Registry.at('GMP::Z#+') expect(sqrtrem.docstring).not_to be_blank expect(sqrtrem.source).not_to be nil expect(sqrtrem.source).not_to be_empty end it "parses GMP::Z methods w/o bodies" do neg = YARD::Registry.at('GMP::Z#neg') expect(neg.docstring).not_to be_blank expect(neg.source).to be nil neg_self = YARD::Registry.at('GMP::Z#neg') expect(neg_self.docstring).not_to be_blank expect(neg_self.source).to be nil end end end yard-0.9.12/spec/parser/base_spec.rb0000755000004100000410000000140713206751010017271 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::Parser::Base do describe "#initialize" do class MyParser < Parser::Base; def initialize(a, b) end end it "takes 2 arguments" do expect { YARD::Parser::Base.new }.to raise_error(ArgumentError, /wrong (number|#) of arguments|given 0, expected 2/) end it "raises NotImplementedError on #initialize" do expect { YARD::Parser::Base.new('a', 'b') }.to raise_error(NotImplementedError) end it "raises NotImplementedError on #parse" do expect { MyParser.new('a', 'b').parse }.to raise_error(NotImplementedError) end it "raises NotImplementedError on #tokenize" do expect { MyParser.new('a', 'b').tokenize }.to raise_error(NotImplementedError) end end end yard-0.9.12/spec/parser/ruby/0000755000004100000410000000000013206751010015774 5ustar www-datawww-datayard-0.9.12/spec/parser/ruby/ruby_parser_spec.rb0000755000004100000410000003273213206751010021702 0ustar www-datawww-data# frozen_string_literal: true RSpec.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 "gets comment line numbers" do s = stmt <<-eof # comment # comment # comment def method; end eof expect(s.comments).to eq "comment\ncomment\ncomment" expect(s.comments_range).to eq(1..3) s = stmt <<-eof # comment # comment def method; end eof expect(s.comments).to eq "comment\ncomment" expect(s.comments_range).to eq(2..3) s = stmt <<-eof # comment # comment def method; end eof expect(s.comments).to eq "comment\ncomment" expect(s.comments_range).to eq(1..2) s = stmt <<-eof # comment def method; end eof expect(s.comments).to eq "comment" expect(s.comments_range).to eq(1..1) s = stmt <<-eof def method; end # comment eof expect(s.comments).to eq "comment" expect(s.comments_range).to eq(1..1) end it "only looks up to two lines back for comments" do s = stmts <<-eof # comments # comments def method; end eof expect(s[1].comments).to eq "comments" s = stmts <<-eof # comments def method; end eof expect(s[1].comments).to eq nil ss = stmts <<-eof # comments def method; end # hello def method2; end eof expect(ss[1].comments).to eq nil expect(ss[2].comments).to eq 'hello' end it "handles block comment followed by line comment" do ss = stmts <<-eof # comments1 =begin comments2 =end # comments3 def hello; end eof expect(ss.last.comments).to eq "comments3" end it "handles block comment followed by block comment" do ss = stmts <<-eof =begin comments1 =end =begin comments2 =end def hello; end eof expect(ss.last.comments.strip).to eq "comments2" end it "handles 1.9 lambda syntax with args" do src = "->(a,b,c=1,*args,&block) { hello_world }" expect(stmt(src).source).to eq src end it "handles 1.9 lambda syntax" do src = "-> { hello_world }" expect(stmt(src).source).to eq src end it "handles standard lambda syntax" do src = "lambda { hello_world }" expect(stmt(src).source).to eq src end it "throws a ParserSyntaxError on invalid code" do expect { stmt("Foo, bar.") }.to raise_error(YARD::Parser::ParserSyntaxError) end it "handles bare hashes as method parameters" do src = "command :a => 1, :b => 2, :c => 3" expect(stmt(src).jump(:command)[1].source).to eq ":a => 1, :b => 2, :c => 3" src = "command a: 1, b: 2, c: 3" expect(stmt(src).jump(:command)[1].source).to eq "a: 1, b: 2, c: 3" end it "handles source for hash syntax" do src = "{ :a => 1, :b => 2, :c => 3 }" expect(stmt(src).jump(:hash).source).to eq "{ :a => 1, :b => 2, :c => 3 }" end it "handles an empty hash" do expect(stmt("{}").jump(:hash).source).to eq "{}" end it "new hash label syntax should show label without colon" do ast = stmt("{ a: 1 }").jump(:label) expect(ast[0]).to eq "a" expect(ast.source).to eq "a:" end it "handles begin/rescue blocks" do ast = stmt("begin; X; rescue => e; Y end").jump(:rescue) expect(ast.source).to eq "rescue => e; Y end" ast = stmt("begin; X; rescue A => e; Y end").jump(:rescue) expect(ast.source).to eq "rescue A => e; Y end" ast = stmt("begin; X; rescue A, B => e; Y end").jump(:rescue) expect(ast.source).to eq "rescue A, B => e; Y end" end it "handles method rescue blocks" do ast = stmt("def x; A; rescue Y; B end") expect(ast.source).to eq "def x; A; rescue Y; B end" expect(ast.jump(:rescue).source).to eq "rescue Y; B end" end it "handles defs with keywords as method name" do ast = stmt("# docstring\nclass A;\ndef class; end\nend") expect(ast.jump(:class).docstring).to eq "docstring" expect(ast.jump(:class).line_range).to eq(2..4) end it "handles defs with unnamed argument with default values" do ast = stmt('def hello(one, two = 2, three = 3) end').jump(:params) expect(ast.source).to eq 'one, two = 2, three = 3' end it "handles defs with splats" do ast = stmt('def hello(one, *two) end').jump(:params) expect(ast.source).to eq 'one, *two' end if YARD.ruby2? it "handles defs with named arguments with default values" do ast = stmt('def hello(one, two: 2, three: 3) end').jump(:params) expect(ast.source).to eq 'one, two: 2, three: 3' end end if NAMED_OPTIONAL_ARGUMENTS it "handles defs with named arguments without default values" do ast = stmt('def hello(one, two:, three:) end').jump(:params) expect(ast.source).to eq 'one, two:, three:' end it "handles defs with double splats" do ast = stmt('def hello(one, **two) end').jump(:params) expect(ast.source).to eq 'one, **two' end end it "ends source properly on array reference" do ast = stmt("AS[0, 1 ] ") expect(ast.source).to eq 'AS[0, 1 ]' ast = stmt('def x(a = S[1]) end').jump(:params) expect(ast.source).to eq 'a = S[1]' end it "ends source properly on if/unless mod" do %w(if unless while).each do |mod| expect(stmt("A=1 #{mod} true").source).to eq "A=1 #{mod} true" end end it "shows proper source for assignment" do expect(stmt("A=1").jump(:assign).source).to eq "A=1" end it "shows proper source for a top_const_ref" do s = stmt("::\nFoo::Bar") expect(s.jump(:top_const_ref).source).to eq "::\nFoo" expect(s).to be_ref expect(s.jump(:top_const_ref)).to be_ref expect(s.source).to eq "::\nFoo::Bar" expect(s.line_range.to_a).to eq [1, 2] end it "shows 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) expect(s.source).to eq src expect(t.map {|x| x[1] }.join).to eq src end it "shows 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) expect(s.source).to eq src expect(t.map {|x| x[1] }.join).to eq src end it "shows 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) expect(s.source).to eq src expect(t.map {|x| x[1] }.join).to eq src end it "shows proper source for string" do ["'", '"'].each do |q| src = "#{q}hello\n\nworld#{q}" s = stmt(src) expect(s.jump(:string_content).source).to eq "hello\n\nworld" expect(s.source).to eq src end src = '("this is a string")' expect(stmt(src).jump(:string_literal).source).to eq '"this is a string"' end %w(w W i I).each do |tok| it "shows proper source for %#{tok}() array" do src = "%#{tok}(\na b c\n d e f\n)" expect(stmt(src).source).to eq src end it "shows proper source for %#{tok}{} array" do src = "%#{tok}{\na b c\n d e f\n}" expect(stmt(src).source).to eq src end end {'i' => :qsymbols_literal, 'I' => :symbols_literal, 'w' => :qwords_literal, 'W' => :words_literal}.each do |id, sym| it "parses %#{id}(...) literals" do [ "TEST = %#{id}(A B C)", "TEST = %#{id}( A B C )", "TEST = %#{id}( \nA \nB \nC \n)", "TEST = %#{id}(\n\nAD\n\nB\n\nC\n\n)", "TEST = %#{id}(\n A\n B\n C\n )" ].each do |str| node = stmt(str).jump(sym) expect(node.source).to eq(str[/(\%#{id}\(.+\))/m, 1]) end end it "tokenizing %#{id}(...) returns correct tokens" do toks = tokenize("TEST = %#{id}(A B C)").flatten expect(toks.count(:tstring_content)).to eq(3) end end it "parses %w() array in constant declaration" do s = stmt(<<-eof) class Foo FOO = %w( foo bar ) end eof expect(s.jump(:qwords_literal).source).to eq '%w( foo bar )' if RUBY_VERSION >= '1.9.3' # ripper fix: array node encapsulates qwords expect(s.jump(:array).source).to eq '%w( foo bar )' end end it "parses %w() array source in object[] parsed context" do s = stmts(<<-eof) {}[:key] FOO = %w( foo bar ) eof expect(s[1].jump(:array).source).to eq '%w( foo bar )' end it "parses %w() array source in object[]= parsed context" do s = stmts(<<-eof) {}[:key] = :value FOO = %w( foo bar ) eof expect(s[1].jump(:array).source).to eq '%w( foo bar )' end it "parses [] as array" do s = stmt(<<-eof) class Foo FOO = ['foo', 'bar'] end eof expect(s.jump(:array).source).to eq "['foo', 'bar']" end it "shows source for unary minus" do expect(stmt("X = - 1").jump(:unary).source).to eq '- 1' end it "shows source for unary exclamation" do expect(stmt("X = !1").jump(:unary).source).to eq '!1' end it "has the correct line range for class/modules" do s = stmt(<<-eof) class Foo def foo; end # Ending comment end eof expect(s.jump(:class).line_range).to eq(1..7) end it "has the correct line range for blocks" do Registry.clear ast = YARD.parse_string(<<-eof).enumerator module A some_method end eof expect(ast.first.block.source.strip).to eq "some_method" end it "finds 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.jump(:comment) expect(comment.type).to eq :comment expect(comment.docstring_hash_flag).to be true expect(comment.docstring.strip).to eq "comment here" expect(ast.first.last.last.type).to eq :comment expect(ast.first.last.last.docstring).to eq "end comment" end it "does not group comments if they don't begin the line" do Registry.clear YARD.parse_string(<<-eof).enumerator class Foo CONST1 = 1 # Comment here CONST2 = 2 # Another comment here end eof expect(Registry.at("Foo::CONST1").docstring).to eq "Comment here" expect(Registry.at("Foo::CONST2").docstring).to eq "Another comment here" end it "handles comments in the middle of a multi-line statement" do Registry.clear YARD.parse_string <<-eof foo # BREAK .bar # Documentation class Baz; end eof expect(Registry.at('Baz')).not_to be_nil expect(Registry.at('Baz').docstring).to eq 'Documentation' end %w(if unless).each do |type| it "does not get confused by modifier '#{type}' statements" do Registry.clear YARD.parse_string(<<-eof).enumerator module Foo #{type} test? # Docstring class Bar # Docstring2 def foo x #{type} true end end end end eof expect(Registry.at("Foo::Bar").docstring).to eq "Docstring" expect(Registry.at("Foo::Bar#foo").docstring).to eq "Docstring2" end it "supports #{type} statements at start of source" do Registry.clear YARD.parse_string <<-eof #{type} condition? class Foo; def bar; #{type} true; end end end end eof expect(log.io.string).to eq "" expect(Registry.at('Foo#bar')).not_to eq nil end it "can handle complex non-modifier '#{type}' statements" do Registry.clear YARD.parse_string <<-eof class Foo def initialize(data, options = Hash.new) #{type} true; raise "error" end @x = ( #{type} 1; true end ) # This line should not blow up end end eof expect(log.io.string).to eq "" expect(Registry.at('Foo#initialize')).not_to eq nil end it "does not add comment blocks to #{type}_mod nodes" do Registry.clear YARD.parse_string(<<-eof).enumerator class Foo # Docstring def bar; end if true end eof expect(Registry.at("Foo#bar").docstring).to eq "Docstring" end end it "removes frozen string line from initial file comments" do YARD.parse_string "# frozen_string_literal: true\n# this is a comment\nclass Foo; end" YARD.parse_string "# Frozen-string-literal: true\n# this is a comment\nclass Bar; end" expect(Registry.at(:Foo).docstring).to eq "this is a comment" expect(Registry.at(:Bar).docstring).to eq "this is a comment" end it "handles compile errors" do expect { stmt(":~$ Do not clobber") }.to raise_error(Parser::ParserSyntaxError) end end end if HAVE_RIPPER yard-0.9.12/spec/parser/ruby/legacy/0000755000004100000410000000000013206751010017240 5ustar www-datawww-datayard-0.9.12/spec/parser/ruby/legacy/token_list_spec.rb0000755000004100000410000000450313206751010022757 0ustar www-datawww-data# frozen_string_literal: true include YARD::Parser::Ruby::Legacy include YARD::Parser::Ruby::Legacy::RubyToken RSpec.describe YARD::Parser::Ruby::Legacy::TokenList do describe "#initialize / #push" do it "accepts a tokenlist (via constructor or push)" do expect { TokenList.new(TokenList.new) }.not_to raise_error expect(TokenList.new.push(TokenList.new("x = 2")).size).to eq 6 end it "accept a token (via constructor or push)" do expect { TokenList.new(Token.new(0, 0)) }.not_to raise_error expect(TokenList.new.push(Token.new(0, 0), Token.new(1, 1)).size).to eq 2 end it "accepts a string and parse it as code (via constructor or push)" do expect { TokenList.new("x = 2") }.not_to raise_error x = TokenList.new x.push("x", "=", "2") expect(x.size).to eq 6 expect(x.to_s).to eq "x\n=\n2\n" end it "does not accept any other input" do expect { TokenList.new(:notcode) }.to raise_error(ArgumentError) end it "does not interpolate string data" do x = TokenList.new('x = "hello #{world}"') expect(x.size).to eq 6 expect(x[4].class).to eq TkDSTRING expect(x.to_s).to eq 'x = "hello #{world}"' + "\n" end it "handles label syntax" do x = TokenList.new('a:1,b:2') expect(x[0].class).to eq TkLABEL expect(x[0].text).to eq 'a:' expect(x[3].class).to eq TkLABEL expect(x[3].text).to eq '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 "only shows the statement portion of the tokens by default" do expect(@t.to_s).to eq "def x" end it "shows ... for the block token if all of the tokens are shown" do expect(@t.to_s(true)).to eq "def x; ... end" end it "ignores ... if show_block = false" do expect(@t.to_s(true, false)).to eq "def x; end" end end end yard-0.9.12/spec/parser/ruby/legacy/statement_list_spec.rb0000755000004100000410000001744313206751010023652 0ustar www-datawww-data# frozen_string_literal: true RSpec.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 "parses dangling block expressions" do s = stmt <<-eof if foo puts 'hi' end eof expect(s.tokens.to_s(true)).to eq "if\n foo\n ...\n end" expect(s.tokens.to_s).to eq "if\n foo" expect(s.block.to_s).to eq "puts 'hi'" s = stmt <<-eof if foo || bar puts 'hi' end eof expect(s.tokens.to_s(true)).to eq "if foo ||\n bar\n ...\n end" expect(s.tokens.to_s).to eq "if foo ||\n bar" expect(s.block.to_s).to eq "puts 'hi'" end it "allows semicolons within parentheses" do s = stmt "(foo; bar)" expect(s.tokens.to_s(true)).to eq "(foo; bar)" expect(s.block).to be nil end it "allows for non-block statements" do s = stmt "hello_world(1, 2, 3)" expect(s.tokens.to_s).to eq "hello_world(1, 2, 3)" expect(s.block).to be nil end it "allows block statements to be used as part of other block statements" do s = stmt "while (foo; bar); foo = 12; end; while" expect(s.tokens.to_s(true)).to eq "while (foo; bar); ... end" expect(s.tokens.to_s).to eq "while (foo; bar)" expect(s.block.to_s).to eq "foo = 12" end it "allows continued processing after a block" do s = stmt "if foo; end.stuff" expect(s.tokens.to_s(true)).to eq "if foo; end.stuff" expect(s.block.to_s).to eq "" s = stmt "if foo; end[stuff]" expect(s.tokens.to_s(true)).to eq "if foo; end[stuff]" expect(s.block.to_s).to eq "" s = stmt "if foo; hi end.map do; 123; end" expect(s.tokens.to_s(true)).to eq "if foo; ... end.map do; 123; end" expect(s.block.to_s).to eq "hi" end it "parses default arguments" do s = stmt "def foo(bar, baz = 1, bang = 2); bar; end" expect(s.tokens.to_s(true)).to eq "def foo(bar, baz = 1, bang = 2) ... end" expect(s.block.to_s).to eq "bar" s = stmt "def foo bar, baz = 1, bang = 2; bar; end" expect(s.tokens.to_s(true)).to eq "def foo bar, baz = 1, bang = 2; ... end" expect(s.block.to_s).to eq "bar" s = stmt "def foo bar , baz = 1 , bang = 2; bar; end" expect(s.tokens.to_s(true)).to eq "def foo bar , baz = 1 , bang = 2; ... end" expect(s.block.to_s).to eq "bar" end it "parses complex default arguments" do s = stmt "def foo(bar, baz = File.new(1, 2), bang = 3); bar; end" expect(s.tokens.to_s(true)).to eq "def foo(bar, baz = File.new(1, 2), bang = 3) ... end" expect(s.block.to_s).to eq "bar" s = stmt "def foo bar, baz = File.new(1, 2), bang = 3; bar; end" expect(s.tokens.to_s(true)).to eq "def foo bar, baz = File.new(1, 2), bang = 3; ... end" expect(s.block.to_s).to eq "bar" s = stmt "def foo bar , baz = File.new(1, 2) , bang = 3; bar; end" expect(s.tokens.to_s(true)).to eq "def foo bar , baz = File.new(1, 2) , bang = 3; ... end" expect(s.block.to_s).to eq "bar" end it "parses blocks with do/end" do s = stmt <<-eof foo do puts 'hi' end eof expect(s.tokens.to_s(true)).to eq "foo do\n ...\n end" expect(s.block.to_s).to eq "puts 'hi'" end it "parses blocks with {}" do s = stmt "x { y }" expect(s.tokens.to_s(true)).to eq "x { ... }" expect(s.block.to_s).to eq "y" s = stmt "x() { y }" expect(s.tokens.to_s(true)).to eq "x() { ... }" expect(s.block.to_s).to eq "y" end it "parses blocks with begin/end" do s = stmt "begin xyz end" expect(s.tokens.to_s(true)).to eq "begin ... end" expect(s.block.to_s).to eq "xyz" end it "parses nested blocks" do s = stmt "foo(:x) { baz(:y) { skippy } }" expect(s.tokens.to_s(true)).to eq "foo(:x) { ... }" expect(s.block.to_s).to eq "baz(:y) { skippy }" end it "does not parse hashes as blocks" do s = stmt "x({})" expect(s.tokens.to_s(true)).to eq "x({})" expect(s.block.to_s).to eq "" s = stmt "x = {}" expect(s.tokens.to_s(true)).to eq "x = {}" expect(s.block.to_s).to eq "" s = stmt "x(y, {})" expect(s.tokens.to_s(true)).to eq "x(y, {})" expect(s.block.to_s).to eq "" end it "parses hashes in blocks with {}" do s = stmt "x {x = {}}" expect(s.tokens.to_s(true)).to eq "x {...}" expect(s.block.to_s).to eq "x = {}" end it "parses blocks with {} in hashes" do s = stmt "[:foo, x {}]" expect(s.tokens.to_s(true)).to eq "[:foo, x {}]" expect(s.block.to_s).to eq "" end it "handles multiple methods" do s = stmt <<-eof def %; end def b; end eof expect(s.to_s).to eq "def %; end" end it "handles nested methods" do s = stmt <<-eof def *(o) def +@; end def ~@ end end eof expect(s.tokens.to_s(true)).to eq "def *(o) ... end" expect(s.block.to_s).to eq "def +@; end\n def ~@\n end" s = stmts(<<-eof) def /(other) 'hi' end def method1 def dynamic; end end eof expect(s[1].to_s).to eq "def method1\n def dynamic; end\n end" end it "gets comment line numbers" do s = stmt <<-eof # comment # comment # comment def method; end eof expect(s.comments).to eq ["comment", "comment", "comment"] expect(s.comments_range).to eq(1..3) s = stmt <<-eof # comment # comment def method; end eof expect(s.comments).to eq ["comment", "comment"] expect(s.comments_range).to eq(2..3) s = stmt <<-eof # comment # comment def method; end eof expect(s.comments).to eq ["comment", "comment"] expect(s.comments_range).to eq(1..2) s = stmt <<-eof # comment def method; end eof expect(s.comments).to eq ["comment"] expect(s.comments_range).to eq(1..1) s = stmt <<-eof def method; end # comment eof expect(s.comments).to eq ["comment"] expect(s.comments_range).to eq(1..1) end it "only looks up to two lines back for comments" do s = stmt <<-eof # comments # comments def method; end eof expect(s.comments).to eq ["comments"] s = stmt <<-eof # comments def method; end eof expect(s.comments).to eq nil ss = stmts <<-eof # comments def method; end # hello def method2; end eof expect(ss[0].comments).to eq nil expect(ss[1].comments).to eq ['hello'] end it "handles 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") expect(s[1].comments).to eq ['Test Test', '', 'Example:', ' example code'] end it "handles elsif blocks" do s = stmts(stmt("if 0\n foo\nelsif 2\n bar\nend\nbaz").block) expect(s.size).to eq 2 expect(s[1].tokens.to_s).to eq "elsif 2" expect(s[1].block.to_s).to eq "bar" end it "handles else blocks" do s = stmts(stmt("if 0\n foo\nelse\n bar\nend\nbaz").block) expect(s.size).to eq 2 expect(s[1].tokens.to_s).to eq "else" expect(s[1].block.to_s).to eq "bar" end it "allows aliasing keywords" do ['do x', 'x do', 'end begin', 'begin end'].each do |a| s = stmt("alias #{a}\ndef foo; end") expect(s.tokens.to_s).to eq "alias #{a}" expect(s.block).to be nil end s = stmt("alias do x if 2 ==\n 2") expect(s.tokens.to_s).to eq "alias do x if 2 ==\n 2" end it "does not open a block on an aliased keyword block opener" do s = stmts(<<-eof) class A; alias x do end class B; end eof expect(s[0].block.to_s).to eq 'alias x do' expect(s.size).to be > 1 end it "converts heredoc to string" do src = "<<-XML\n foo\n\nXML" s = stmt(src) expect(s.source).to eq '"foo\n\n"' end end yard-0.9.12/spec/parser/ruby/ast_node_spec.rb0000755000004100000410000000223213206751010021131 0ustar www-datawww-data# frozen_string_literal: true require 'pp' require 'stringio' include YARD::Parser::Ruby RSpec.describe YARD::Parser::Ruby::AstNode do describe "#jump" do it "jumps to the first specific inner node if found" do ast = s(:paren, s(:paren, s(:params, s(s(:ident, "hi"), s(:ident, "bye"))))) expect(ast.jump(:params)[0][0].type).to equal(:ident) end it "returns the original ast if no inner node is found" do ast = s(:paren, s(:list, s(:list, s(s(:ident, "hi"), s(:ident, "bye"))))) expect(ast.jump(:params).object_id).to eq ast.object_id end end describe "#pretty_print" do it "shows 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' expect(out.string).to eq "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.9.12/spec/parser/ruby/token_resolver_spec.rb0000755000004100000410000001006313206751010022377 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::Parser::Ruby::TokenResolver do before(:all) do YARD.parse_string <<-eof module A def nomatch; end module B class C def initialize; end # @return [A::B::C] def self.foo; end # @return [self] def self.foo2; end def bar; end # @return [nil, D] def baz; end # @return [nil] # @return [D] def baz2; end # @overload qux(a) # @return [nil] # @overload qux(b) # @return [D] def qux; end end class SubC < C end end end module D def baz; end end class Q def method; end # @return [Q] def self.q; end end eof end def tokens_match expect(@resolved.map {|t| t.first.last }.join).to eq @src end def objs_match(*objects) other_objs = @resolved.reject {|_, o| !o }.map {|_, o| o.path } expect(other_objs).to eq objects.flatten tokens_match end def tokenize(src, object = nil) @src = src @resolver = YARD::Parser::Ruby::TokenResolver.new(src, object) @resolved = @resolver.map {|t, o| [t[0, 2], o] } end it "returns regular tokens" do str = "def foo; Z::X::Y end" tokenize(str) tokens_match end it "resolves objects in compound constant paths" do tokenize "A::B::C" objs_match "A", "A::B", "A::B::C" end it "ignores full constant path if it breaks at beginning" do tokenize "E::A::B::C" objs_match [] end it "ignores rest of constant path if sub-objects don't match" do tokenize "D::A::B::C" objs_match "D" end it "resets parsing at non-op tokens" do tokenize "A::B::C < Q" objs_match "A", "A::B", "A::B::C", "Q" end it "does not restart constant path" do tokenize "A::B::D::A" objs_match "A", "A::B" end it "resolves objects from base namespace" do tokenize "A::B::C C", Registry.at("A::B") objs_match "A", "A::B", "A::B::C", "A::B::C" end it "resolves methods" do tokenize "A::B::C.foo" objs_match "A", "A::B", "A::B::C", "A::B::C.foo" end it "supports 'new' constructor method" do tokenize "A::B::C.new" objs_match "A", "A::B", "A::B::C", "A::B::C#initialize" end it "skips constructor method if not found but continues resolving" do tokenize "Q.new.method" objs_match "Q", "Q#method" end it "resolves methods in inheritance tree" do tokenize "A::B::SubC.new" objs_match "A", "A::B", "A::B::SubC", "A::B::C#initialize" end it "parses compound method call chains based on return type" do tokenize "A::B::C.foo.baz" objs_match "A", "A::B", "A::B::C", "A::B::C.foo", "A::B::C#baz" end it "stops resolving if return types not found" do tokenize "A::B::C.foo.bar.baz.baz" objs_match "A", "A::B", "A::B::C", "A::B::C.foo", "A::B::C#bar" end it "handles multiple return types (returns first valid type match)" do tokenize "A::B::C.foo.baz.baz" objs_match "A", "A::B", "A::B::C", "A::B::C.foo", "A::B::C#baz", "D#baz" end it "doesn't perform lexical matching on methods" do tokenize "A::B::C.nomatch" objs_match "A", "A::B", "A::B::C" end it "handles multiple return tags (returns first valid type match)" do tokenize "A::B::C.foo.baz2.baz" objs_match "A", "A::B", "A::B::C", "A::B::C.foo", "A::B::C#baz2", "D#baz" end it "handles self as return type" do tokenize "A::B::C.foo2.baz" objs_match "A", "A::B", "A::B::C", "A::B::C.foo2", "A::B::C#baz" end it "handles multiple return tags inside overload tags" do tokenize "A::B::C.foo.qux.baz" objs_match "A", "A::B", "A::B::C", "A::B::C.foo", "A::B::C#qux", "D#baz" end it "resolves method calls with arguments" do tokenize "Q.q(A::B, A::B::C.foo().bar).q.q" objs_match "Q", "Q.q", "A", "A::B", "A", "A::B", "A::B::C", "A::B::C.foo", "A::B::C#bar", "Q.q", "Q.q" end end if HAVE_RIPPER yard-0.9.12/spec/i18n/0000755000004100000410000000000013206751010014276 5ustar www-datawww-datayard-0.9.12/spec/i18n/pot_generator_spec.rb0000755000004100000410000002044013206751010020510 0ustar www-datawww-data# frozen_string_literal: true RSpec.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 "generates the default header" do current_time = Time.parse("2011-11-20 22:17+0900") allow(@generator).to receive(:current_time).and_return(current_time) pot_creation_date = current_time.strftime("%Y-%m-%d %H:%M%z") expect(@generator.generate).to eq <<-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: #{pot_creation_date}\\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 "generates messages in location order" do allow(@generator).to receive(: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) expect(@generator.generate).to eq <<-'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 = String.new("") message = YARD::I18n::Message.new(message_id) @generator.send(:generate_message, pot, message) pot end it "escapes <\\>" do expect(generate_message_pot("hello \\ world")).to eq <<-'eop' msgid "hello \\ world" msgstr "" eop end it "escapes <\">" do expect(generate_message_pot("hello \" world")).to eq <<-'eop' msgid "hello \" world" msgstr "" eop end it "escapes <\\n>" do expect(generate_message_pot("hello \n world")).to eq <<-'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 "extracts at 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]) expect(@generator.messages).to eq create_messages( "An alias to {Parser::SourceParser}'s parsing method" => { :locations => [], :comments => ["YARD.parse"] } ) end it "extracts at 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]) expect(@generator.messages).to eq create_messages( "An alias to {Parser::SourceParser}'s parsing method" => { :locations => [["yard.rb", 13]], :comments => ["YARD.parse"] } ) end it "extracts at 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]) expect(@generator.messages).to eq create_messages( "tag|see|Parser::SourceParser.parse" => { :locations => [["yard.rb", 12]], :comments => ["@see"] } ) end it "extracts at 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]) expect(@generator.messages).to eq 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 "extracts at 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]) expect(@generator.messages).to eq 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 it "extracts at overload tag recursively" do object = YARD::CodeObjects::MethodObject.new(@yard, :parse, :module) do |o| o.docstring = <<-eod @overload foo(i) docstring foo(i) @param [Integer] i integer parameter eod end @generator.parse_objects([object]) expect(@generator.messages).to eq create_messages( "tag|overload|foo" => { :locations => [], :comments => ["@overload"] }, "docstring foo(i)" => { :locations => [], :comments => ["YARD.parse"] }, "tag|param|i" => { :locations => [], :comments => ["@param [Integer]"] }, "integer parameter" => { :locations => [], :comments => ["@param [Integer] i"] } ) end end describe "File" do it "extracts at attribute" do path = "GettingStarted.md" text = <<-eor # @title Getting Started Guide # Getting Started with YARD eor allow(File).to receive(:open).with(path).and_yield(StringIO.new(text)) allow(File).to receive(:read).with(path).and_return(text) file = YARD::CodeObjects::ExtraFileObject.new(path) @generator.parse_files([file]) expect(@generator.messages).to eq create_messages( "Getting Started Guide" => { :locations => [[path, 1]], :comments => ["title"] }, "# Getting Started with YARD" => { :locations => [[path, 3]], :comments => [] } ) end it "extracts at 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 allow(File).to receive(:open).with(path).and_yield(StringIO.new(text)) allow(File).to receive(:read).with(path).and_return(text) file = YARD::CodeObjects::ExtraFileObject.new(path) @generator.parse_files([file]) expect(@generator.messages).to eq create_messages( paragraph1 => { :locations => [[path, 1]], :comments => [] }, paragraph2 => { :locations => [[path, 4]], :comments => [] } ) end end end yard-0.9.12/spec/i18n/text_spec.rb0000755000004100000410000000754313206751010016635 0ustar www-datawww-data# frozen_string_literal: true RSpec.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 "extracts at attribute" do text = <<-eot # @title Getting Started Guide # Getting Started with YARD eot expect(extract_messages(text, :have_header => true)).to eq( [[:attribute, "title", "Getting Started Guide", 1], [:paragraph, "# Getting Started with YARD", 3]] ) end it "ignores markup line" do text = <<-eot #!markdown # @title Getting Started Guide # Getting Started with YARD eot expect(extract_messages(text, :have_header => true)).to eq( [[:attribute, "title", "Getting Started Guide", 2], [:paragraph, "# Getting Started with YARD", 4]] ) end it "terminates header block by markup line not at the first line" do text = <<-eot # @title Getting Started Guide #!markdown # Getting Started with YARD eot expect(extract_messages(text, :have_header => true)).to eq( [[:attribute, "title", "Getting Started Guide", 1], [:paragraph, "#!markdown", 2], [:paragraph, "# Getting Started with YARD", 4]] ) end end describe "Body" do it "splits 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 expect(extract_messages(text)).to eq( [[: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 "extracts at attribute" do text = <<-eot # @title Hello # Getting Started with YARD Paragraph. eot expect(translate(text, :have_header => true)).to eq <<-eot # @title Bonjour (Hello in fr) # Getting Started with YARD Paragraph. eot end it "ignores markup line" do text = <<-eot #!markdown # @title Hello # Getting Started with YARD Paragraph. eot expect(translate(text, :have_header => true)).to eq <<-eot #!markdown # @title Bonjour (Hello in fr) # Getting Started with YARD Paragraph. eot end end describe "Body" do it "splits to paragraphs" do paragraph1 = <<-eop.strip Paragraph 1. eop paragraph2 = <<-eop.strip Paragraph 2. eop text = <<-eot #{paragraph1} #{paragraph2} eot expect(translate(text)).to eq <<-eot Paragraphe 1. Paragraphe 2. eot end it "does not modify non-translated message" do nonexistent_paragraph = <<-eop.strip Nonexsitent paragraph. eop text = <<-eot #{nonexistent_paragraph} eot expect(translate(text)).to eq <<-eot #{nonexistent_paragraph} eot end it "keeps empty lines" do text = <<-eot Paragraph 1. Paragraph 2. eot expect(translate(text)).to eq <<-eot Paragraphe 1. Paragraphe 2. eot end end end end yard-0.9.12/spec/i18n/locale_spec.rb0000755000004100000410000000371413206751010017104 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::I18n::Locale do def locale(name) YARD::I18n::Locale.new(name) end before do @locale = locale("fr") end describe "#name" do it "returns name" do expect(locale("fr").name).to eq "fr" end end describe "#load" do it "returns false for nonexistent PO" do expect(File).to receive(:exist?).with('foo/fr.po').and_return(false) expect(@locale.load('foo')).to be 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 "returns 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 expect(File).to receive(:exist?).with('foo/fr.po').and_return(true) expect(GetText::POParser).to receive(:new).and_return(parser) expect(parser).to receive(:parse_file) do |file, hash| expect(file).to eq 'foo/fr.po' parser.parse(String.new(data), hash) end expect(@locale.load('foo')).to be true expect(@locale.translate('Hello')).to eq "Bonjour" end end describe "#translate" do before do messages = @locale.instance_variable_get(:@messages) messages["Hello"] = "Bonjour" end it "returns translated string for existent string" do expect(@locale.translate("Hello")) == "Bonjour" end it "returns original string for nonexistent string" do expect(@locale.translate("nonexistent")) == "nonexistent" end end end yard-0.9.12/spec/i18n/messages_spec.rb0000755000004100000410000000330613206751010017451 0ustar www-datawww-data# frozen_string_literal: true RSpec.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 "enumerates messages" do @messages.register("Hello World!") @messages.register("Title") enumerated_messages = [] @messages.each do |message| enumerated_messages << message end enumerated_messages = enumerated_messages.sort_by(&:id) expect(enumerated_messages).to eq [message("Hello World!"), message("Title")] end it "does not yield any message if there are none" do enumerated_messages = [] @messages.each do |message| enumerated_messages << message end expect(enumerated_messages).to eq [] end end describe "#[]" do it "returns registered message" do @messages.register("Hello World!") expect(@messages["Hello World!"]).to eq message("Hello World!") end it "returns nil for nonexistent message ID" do expect(@messages["Hello World!"]).to eq nil end end describe "#register" do it "returns registered message" do expect(@messages.register("Hello World!")).to eq message("Hello World!") end it "returns existent message" do message = @messages.register("Hello World!") expect(@messages.register("Hello World!").object_id).to eq message.object_id end end describe "#==" do it "returns true for same value messages" do @messages.register("Hello World!") other_messages = messages other_messages.register("Hello World!") expect(@messages).to eq other_messages end end end yard-0.9.12/spec/i18n/message_spec.rb0000755000004100000410000000246713206751010017275 0ustar www-datawww-data# frozen_string_literal: true RSpec.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 "returns ID" do expect(message("Hello World!").id).to eq "Hello World!" end end describe "#add_location" do it "adds some locations" do @message.add_location("hello.rb", 10) @message.add_location("message.rb", 5) expect(@message.locations).to eq Set.new([["hello.rb", 10], ["message.rb", 5]]) end end describe "#add_comment" do it "adds some comments" do @message.add_comment("YARD.title") @message.add_comment("Hello#message") expect(@message.comments).to eq Set.new(["YARD.title", "Hello#message"]) end end describe "#==" do it "returns 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 expect(@message).to eq other_message end end end yard-0.9.12/spec/serializers/0000755000004100000410000000000013206751010016053 5ustar www-datawww-datayard-0.9.12/spec/serializers/data/0000755000004100000410000000000013206751010016764 5ustar www-datawww-datayard-0.9.12/spec/serializers/data/serialized_yardoc/0000755000004100000410000000000013206751010022460 5ustar www-datawww-datayard-0.9.12/spec/serializers/data/serialized_yardoc/checksums0000755000004100000410000000006113206751010024370 0ustar www-datawww-datatest.rb 80e5834ff1e98223761615c0917ff9b77b7ae057 yard-0.9.12/spec/serializers/data/serialized_yardoc/objects/0000755000004100000410000000000013206751010024111 5ustar www-datawww-datayard-0.9.12/spec/serializers/data/serialized_yardoc/objects/Foo/0000755000004100000410000000000013206751010024634 5ustar www-datawww-datayard-0.9.12/spec/serializers/data/serialized_yardoc/objects/Foo/baz_i.dat0000755000004100000410000000062313206751010026416 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.9.12/spec/serializers/data/serialized_yardoc/objects/Foo/bar_i.dat0000755000004100000410000000063713206751010026413 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.9.12/spec/serializers/data/serialized_yardoc/objects/root.dat0000755000004100000410000000075013206751010025573 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.9.12/spec/serializers/data/serialized_yardoc/objects/Foo.dat0000755000004100000410000000126213206751010025332 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.9.12/spec/serializers/data/serialized_yardoc/proxy_types0000755000004100000410000000003113206751010025005 0ustar www-datawww-data{I" Object:EF: classyard-0.9.12/spec/serializers/spec_helper.rb0000755000004100000410000000005313206751010020672 0ustar www-datawww-data# frozen_string_literal: true include YARD yard-0.9.12/spec/serializers/yardoc_serializer_spec.rb0000755000004100000410000000540013206751010023126 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + "/spec_helper" instance_eval do class YARD::Serializers::YardocSerializer public :dump public :internal_dump end end RSpec.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 "maintains object equality when loading a dumped object" do newfoo = @serializer.internal_dump(@foo) expect(newfoo).to equal(@foo) expect(newfoo).to eq @foo expect(@foo).to equal(newfoo) expect(@foo).to eq newfoo expect(newfoo.hash).to eq @foo.hash end it "maintains hash key equality when loading a dumped object" do newfoo = @serializer.internal_dump(@foo) expect(@foo => 1).to have_key(newfoo) expect(newfoo => 1).to have_key(@foo) end end describe "#serialize" do it "accepts a hash of codeobjects (and write to root)" do data = {:root => Registry.root} marshaldata = Marshal.dump(data) filemock = double(:file) expect(filemock).to receive(:write).with(marshaldata) expect(File).to receive(:open!).with('.yardoc/objects/root.dat', 'wb').and_yield(filemock) @serializer.serialize(data) end end describe "#lock_for_writing" do it "creates a lock file during writing and cleans up" do expect(File).to receive(:open!).with(@serializer.processing_path, 'w') expect(File).to receive(:exist?).with(@serializer.processing_path).exactly(2).times.and_return(true) expect(File).to receive(:unlink).with(@serializer.processing_path) @serializer.lock_for_writing do expect(@serializer.locked_for_writing?).to eq true end end end describe "#complete?" do it "returns false if complete file does not exist" do allow(File).to receive(:exist?).with(@serializer.complete_lock_path).and_return(false) allow(File).to receive(:exist?).with(@serializer.processing_path).and_return(false) expect(@serializer.complete?).to eq false end it "returns false if processing file exists" do allow(File).to receive(:exist?).with(@serializer.complete_lock_path).and_return(true) allow(File).to receive(:exist?).with(@serializer.processing_path).and_return(true) expect(@serializer.complete?).to eq false end it "returns true if complete file exists with no processing file" do allow(File).to receive(:exist?).with(@serializer.complete_lock_path).and_return(true) allow(File).to receive(:exist?).with(@serializer.processing_path).and_return(false) expect(@serializer.complete?).to eq true end end end yard-0.9.12/spec/serializers/file_system_serializer_spec.rb0000755000004100000410000001137413206751010024177 0ustar www-datawww-data# frozen_string_literal: true require File.join(File.dirname(__FILE__), "spec_helper") require 'stringio' RSpec.describe YARD::Serializers::FileSystemSerializer do before do allow(FileUtils).to receive(:mkdir_p) allow(File).to receive(:open) end describe "#basepath" do it "defaults the base path to the 'doc/'" do obj = Serializers::FileSystemSerializer.new expect(obj.basepath).to eq 'doc' end end describe "#extension" do it "defaults the file extension to .html" do obj = Serializers::FileSystemSerializer.new expect(obj.extension).to eq "html" end end describe "#serialized_path" do it "allows no extension to be used" do obj = Serializers::FileSystemSerializer.new :extension => nil yard = CodeObjects::ClassObject.new(nil, :FooBar) expect(obj.serialized_path(yard)).to eq 'FooBar' end it "serializes to top-level-namespace for root" do obj = Serializers::FileSystemSerializer.new :extension => nil expect(obj.serialized_path(Registry.root)).to eq "top-level-namespace" end it "returns serialized_path for a String" do s = Serializers::FileSystemSerializer.new(:basepath => 'foo', :extension => 'txt') expect(s.serialized_path('test.txt')).to eq 'test.txt' end it "removes special chars from path" do m = CodeObjects::MethodObject.new(nil, 'a') s = Serializers::FileSystemSerializer.new {: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| allow(m).to receive(:name).and_return(meth) expect(s.serialized_path(m)).to eq value end end it "handles ExtraFileObject's" do s = Serializers::FileSystemSerializer.new e = CodeObjects::ExtraFileObject.new('filename.txt', '') expect(s.serialized_path(e)).to eq 'file.filename.html' end it "differentiates 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) expect(s.serialized_path(m1)).not_to eq s.serialized_path(m2) end it "serializes 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) expect(serializer.serialized_path(object)).to eq "Foo/bar_i.html" end it "maps matching case sensitive object names to different files on disk" do Registry.clear o1 = CodeObjects::ClassObject.new(:root, "AB") o2 = CodeObjects::ClassObject.new(:root, "Ab") s = Serializers::FileSystemSerializer.new expect([["AB_.html", "Ab.html"], ["AB.html", "Ab_.html"]]).to include( [s.serialized_path(o1), s.serialized_path(o2)] ) end it "handles case sensitivity of nested paths for objects with matching names" do Registry.clear YARD.parse_string <<-eof class Abc; class D; end end class ABC; class D; end end eof s = Serializers::FileSystemSerializer.new expect(s.serialized_path(Registry.at('ABC::D'))).to eq "ABC/D.html" expect(s.serialized_path(Registry.at('Abc::D'))).to eq "Abc/D.html" end end describe "#serialize" do it "serializes 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 expect(File).to receive(:open).with(path, 'wb').and_yield(io) expect(io).to receive(:write).with("data") s = Serializers::FileSystemSerializer.new(:basepath => 'foo', :extension => 'txt') s.serialize(obj, "data") end end it "guarantees 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) expect(FileUtils).to receive(:mkdir_p).once.with('doc/Really/Long/PathName') s = Serializers::FileSystemSerializer.new s.serialize(obj, "data") end end end yard-0.9.12/spec/code_objects/0000755000004100000410000000000013206751010016142 5ustar www-datawww-datayard-0.9.12/spec/code_objects/proxy_spec.rb0000755000004100000410000001034713206751010020672 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe YARD::CodeObjects::Proxy do before { Registry.clear } it "returns the object if it's in the Registry" do ModuleObject.new(:root, :YARD) proxyobj = P(:root, :YARD) expect(proxyobj.type).to eq :module expect(Proxy === proxyobj).to be false end it "handles complex string namespaces" do ModuleObject.new(:root, :A) ModuleObject.new(P(nil, :A), :B) expect(P(:root, "A::B")).to be_instance_of(ModuleObject) end it "does not return true to Proxy === obj if obj is a Proxy class holding a resolved object" do expect(Proxy === P(:root, 'a')).to be true expect(Proxy === P(:root)).to be false MethodObject.new(:root, 'a') expect(Proxy === P(:root, 'a')).to be false x = Proxy.new(:root, 'a') expect(Proxy === x).to be false end it "returns the object if it's an included Module" do yardobj = ModuleObject.new(:root, :YARD) pathobj = ClassObject.new(:root, :TestClass) pathobj.instance_mixins << yardobj expect(P(P(nil, :TestClass), :YARD)).to be_instance_of(ModuleObject) end it "responds to respond_to?" do ClassObject.new(:root, :Object) ModuleObject.new(:root, :YARD) expect(P(:YARD).respond_to?(:children)).to be true expect(P(:NOTYARD).respond_to?(:children)).to be false expect(P(:YARD).respond_to?(:initialize)).to be false expect(P(:YARD).respond_to?(:initialize, true)).to be true expect(P(:NOTYARD).respond_to?(:initialize)).to be false expect(P(:NOTYARD).respond_to?(:initialize, true)).to be true end it "makes itself obvious that it's a proxy" do pathobj = P(:root, :YARD) expect(pathobj.class).to eq Proxy expect(Proxy === pathobj).to be true end it "pretends it's the object's type if it can resolve" do ModuleObject.new(:root, :YARD) proxyobj = P(:root, :YARD) expect(proxyobj).to be_instance_of(ModuleObject) end it "handles instance method names" do obj = P(nil, '#test') expect(obj.name).to eq :test expect(obj.path).to eq "#test" expect(obj.namespace).to eq Registry.root end it "handles instance method names under a namespace" do pathobj = ModuleObject.new(:root, :YARD) obj = P(pathobj, "A::B#test") expect(obj.name).to eq :test expect(obj.path).to eq "A::B#test" end it "allows type to be changed" do obj = P("InvalidClass") expect(obj.type).to eq :proxy expect(Proxy === obj).to be true obj.type = :class expect(obj.type).to eq :class end it "does NOT retain a type change between Proxy objects" do P("InvalidClass").type = :class expect(P("InvalidClass").type).to eq :proxy end it "uses 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 expect(proxy.path).to eq 'Foo.Bar' end it "allows type in initializer" do expect(Proxy.new(Registry.root, 'Foo', :method).type).to eq :method expect(P(Registry.root, 'Foo', :method).type).to eq :method end it "never equals Registry.root" do expect(P("MYPROXY")).not_to eq Registry.root expect(P("X::A")).not_to eq Registry.root end it "resets namespace and name when object is resolved" do obj1 = ModuleObject.new(:root, :YARD) obj2 = ModuleObject.new(:root, :NOTYARD) resolved = Proxy.new(obj2, :YARD) expect(resolved).to eq obj1 expect(resolved.namespace).to eq Registry.root expect(resolved.name).to eq :YARD end it "ensures that the correct object was resolved" do foo = ModuleObject.new(:root, :Foo) foobar = ModuleObject.new(foo, :Bar) ClassObject.new(foo, :Baz) # Remember, we're looking for Qux::Bar, not just 'Bar' proxy = Proxy.new(foobar, 'Foo::Qux::Bar') expect(proxy.type).to eq :proxy qux = ModuleObject.new(foo, :Qux) ModuleObject.new(qux, :Bar) # Now it should resolve expect(proxy.type).to eq :module end it "handles constant names in namespaces" do YARD.parse_string <<-eof module A; end; B = A module B::C; def foo; end end eof expect(Proxy.new(:root, 'B::C')).to eq Registry.at('A::C') end end yard-0.9.12/spec/code_objects/extra_file_object_spec.rb0000755000004100000410000001311213206751010023152 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe YARD::CodeObjects::ExtraFileObject do describe "#initialize" do it "attempts to read contents from filesystem if contents=nil" do expect(File).to receive(:read).with('file.txt').and_return('') ExtraFileObject.new('file.txt') end it "raises Errno::ENOENT if contents=nil and file does not exist" do expect { ExtraFileObject.new('file.txt') }.to raise_error(Errno::ENOENT) end it "does not attempt to read from disk if contents are provided" do # TODO: no assertions here! ExtraFileObject.new('file.txt', 'CONTENTS') end it "sets filename to filename" do file = ExtraFileObject.new('a/b/c/file.txt', 'CONTENTS') expect(file.filename).to eq "a/b/c/file.txt" end it "parses out attributes at top of the file" do file = ExtraFileObject.new('file.txt', "# @title X\n# @some_attribute Y\nFOO BAR") expect(file.attributes[:title]).to eq "X" expect(file.attributes[:some_attribute]).to eq "Y" expect(file.contents).to eq "FOO BAR" end it "allows whitespace prior to '#' marker when parsing attributes" do file = ExtraFileObject.new('file.txt', " \t # @title X\nFOO BAR") expect(file.attributes[:title]).to eq "X" expect(file.contents).to eq "FOO BAR" end it "allows the attributes section to be wrapped in an HTML comment" do file = ExtraFileObject.new('file.txt', "\nFOO BAR") expect(file.attributes[:title]).to eq "X" expect(file.contents).to eq "FOO BAR" end it "allows whitespace around ignored HTML comment" do file = ExtraFileObject.new('file.txt', " \t \nFOO BAR") expect(file.attributes[:title]).to eq "X" expect(file.contents).to eq "FOO BAR" end it "parses out old-style #!markup shebang format" do file = ExtraFileObject.new('file.txt', "#!foobar\nHello") expect(file.attributes[:markup]).to eq "foobar" end it "does not parse old-style #!markup if any whitespace is found" do file = ExtraFileObject.new('file.txt', " #!foobar\nHello") expect(file.attributes[:markup]).to be nil expect(file.contents).to eq " #!foobar\nHello" end it "does not parse out attributes if there are newlines prior to attributes" do file = ExtraFileObject.new('file.txt', "\n# @title\nFOO BAR") expect(file.attributes).to be_empty expect(file.contents).to eq "\n# @title\nFOO BAR" end it "sets contents to data after attributes" do file = ExtraFileObject.new('file.txt', "# @title\nFOO BAR") expect(file.contents).to eq "FOO BAR" end it "preserves newlines" do file = ExtraFileObject.new('file.txt', "FOO\r\nBAR\nBAZ") expect(file.contents).to eq "FOO\r\nBAR\nBAZ" end it "does not include newlines in attribute data" do file = ExtraFileObject.new('file.txt', "# @title FooBar\r\nHello world") expect(file.attributes[:title]).to eq "FooBar" end it "forces encoding to @encoding attribute if present" do expect(log).not_to receive(:warn) data = String.new("# @encoding sjis\nFOO") data.force_encoding('binary') file = ExtraFileObject.new('file.txt', data) expect(['Shift_JIS', 'Windows-31J']).to include(file.contents.encoding.to_s) end if YARD.ruby19? it "warns if @encoding is invalid" do expect(log).to receive(:warn).with("Invalid encoding `INVALID' in file.txt") data = String.new("# @encoding INVALID\nFOO") encoding = data.encoding file = ExtraFileObject.new('file.txt', data) expect(file.contents.encoding).to eq encoding end if YARD.ruby19? it "ignores encoding in 1.8.x (or encoding-unaware platforms)" do expect(log).not_to receive(:warn) ExtraFileObject.new('file.txt', "# @encoding INVALID\nFOO") end if YARD.ruby18? it "attempts to re-parse data as 8-bit ascii if parsing fails" do expect(log).not_to receive(:warn) str, out = *([String.new("\xB0")] * 2) if str.respond_to?(:force_encoding) str.force_encoding('utf-8') out.force_encoding('binary') end file = ExtraFileObject.new('file.txt', str) expect(file.contents).to eq out end end describe "#name" do it "returns basename (not extension) of filename" do file = ExtraFileObject.new('file.txt', '') expect(file.name).to eq 'file' end end describe "#title" do it "returns @title attribute if present" do file = ExtraFileObject.new('file.txt', '# @title FOO') expect(file.title).to eq 'FOO' end it "returns #name if no @title attribute exists" do file = ExtraFileObject.new('file.txt', '') expect(file.title).to eq 'file' end end describe "#locale=" do it "translates 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' expect(Registry).to receive(:locale).with('fr').and_return(fr_locale) expect(file.contents).to eq 'Bonjour' end end describe "#==" do it "defines equality based on filename alone" do file1 = ExtraFileObject.new('file.txt', 'A') file2 = ExtraFileObject.new('file.txt', 'B') expect(file1).to eq file2 expect(file1).to eql file2 expect(file1).to equal file2 # Another way to test the equality interface a = [file1] a |= [file2] expect(a.size).to eq 1 end end end yard-0.9.12/spec/code_objects/class_object_spec.rb0000755000004100000410000001543213206751010022144 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.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 "shows the proper inheritance tree" do expect(@yard.inheritance_tree).to eq [@yard, @superyard, P(:String)] end it "shows proper inheritance tree when mixins are included" do expect(@yard.inheritance_tree(true)).to eq [@yard, @mixin, @superyard, @mixin4, @mixin2, @mixin3, P(:String)] end it "does 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) expect(@class2.mixins).to eq [] end it "lists class mixins in inheritance tree" do mod = ModuleObject.new(:root, :ClassMethods) klass = ClassObject.new(:root, :ReceivingClass) klass.class_mixins << mod expect(klass.inheritance_tree(true)).to eq [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 "shows inherited methods by default" do meths = P(:YARD).meths expect(meths).to include(P("YARD#mymethod")) expect(meths).to include(P("SuperYard#foo")) expect(meths).to include(P("SuperYard#foo2")) expect(meths).to include(P("SuperYard.bar")) end it "allows :inherited to be set to false" do meths = P(:YARD).meths(:inherited => false) expect(meths).to include(P("YARD#mymethod")) expect(meths).not_to include(P("SuperYard#foo")) expect(meths).not_to include(P("SuperYard#foo2")) expect(meths).not_to include(P("SuperYard.bar")) end it "does not show overridden methods" do meths = P(:YARD).meths expect(meths).to include(P("YARD#bar")) expect(meths).not_to include(P("SuperYard#bar")) meths = P(:YARD).inherited_meths expect(meths).not_to include(P("YARD#bar")) expect(meths).not_to include(P("YARD#mymethod")) expect(meths).to include(P("SuperYard#foo")) expect(meths).to include(P("SuperYard#foo2")) expect(meths).to include(P("SuperYard.bar")) end it "does not show inherited methods overridden by other subclasses" do meths = P(:YARD).inherited_meths expect(meths).to include(P('MiddleYard#middle')) expect(meths).not_to include(P('SuperYard#middle')) end it "shows mixed in methods before superclass method" do meths = P(:FinalYard).meths expect(meths).to include(P('IncludedYard#foo')) expect(meths).not_to 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 "lists inherited constants by default" do consts = P(:SubYard).constants expect(consts).to include(P("YARD::CONST1")) expect(consts).to include(P("SubYard::CONST3")) consts = P(:SubYard).inherited_constants expect(consts).to include(P("YARD::CONST1")) expect(consts).not_to include(P("YARD::CONST2")) expect(consts).not_to include(P("SubYard::CONST2")) expect(consts).not_to include(P("SubYard::CONST3")) end it "does not list inherited constants if turned off" do consts = P(:SubYard).constants(:inherited => false) expect(consts).not_to include(P("YARD::CONST1")) expect(consts).to include(P("SubYard::CONST3")) end it "does not include an inherited constant if it is overridden by the object" do consts = P(:SubYard).constants expect(consts).to include(P("SubYard::CONST2")) expect(consts).not_to include(P("YARD::CONST2")) end it "does not include an inherited constant if it is overridden by another subclass" do consts = P(:SubYard).inherited_constants expect(consts).to include(P("SUPERYARD::CONST4")) expect(consts).not_to include(P("YARD::CONST4")) end it "does not set a superclass on BasicObject class" do o = ClassObject.new(:root, :BasicObject) expect(o.superclass).to be nil end it "sets superclass of Object to BasicObject" do o = ClassObject.new(:root, :Object) expect(o.superclass).to eq P(:BasicObject) end it "raises ArgumentError if superclass == self" do expect do ClassObject.new(:root, :Object) do |o| o.superclass = :Object end end.to raise_error(ArgumentError) end it "tells 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 ClassObject.new(:root, :Object) o.superclass = :Object expect(o.is_exception?).to be false o.superclass = :Exception expect(o.is_exception?).to be true o.superclass = :NoMethodError expect(o.is_exception?).to be true o.superclass = o2 expect(o.is_exception?).to be true o.superclass = o3 expect(o.is_exception?).to be true end it "does not raise ArgumentError if superclass is proxy in different namespace" do expect do ClassObject.new(:root, :X) do |o| o.superclass = P('OTHER::X') end end.not_to raise_error end end end yard-0.9.12/spec/code_objects/spec_helper.rb0000755000004100000410000000006313206751010020762 0ustar www-datawww-data# frozen_string_literal: true include CodeObjects yard-0.9.12/spec/code_objects/constants_spec.rb0000755000004100000410000000675013206751010021530 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe YARD::CodeObjects do def silence_warnings origverb = $VERBOSE $VERBOSE = nil yield $VERBOSE = origverb end describe :CONSTANTMATCH do it "matches a constant" do expect("Constant"[CodeObjects::CONSTANTMATCH]).to eq "Constant" expect("identifier"[CodeObjects::CONSTANTMATCH]).to be nil expect("File.new"[CodeObjects::CONSTANTMATCH]).to eq "File" end end describe :CONSTANTSTART do it "matches a constant" do expect("Constant"[CodeObjects::CONSTANTSTART]).to eq "C" expect("identifier"[CodeObjects::CONSTANTSTART]).to be nil expect("File.new"[CodeObjects::CONSTANTSTART]).to eq "F" end end describe :NAMESPACEMATCH do it "matches a namespace (multiple constants with ::)" do expect("Constant"[CodeObjects::NAMESPACEMATCH]).to eq "Constant" expect("A::B::C.new"[CodeObjects::NAMESPACEMATCH]).to eq "A::B::C" end end describe :METHODNAMEMATCH do it "matches a method name" do expect("method"[CodeObjects::METHODNAMEMATCH]).to eq "method" expect("[]()"[CodeObjects::METHODNAMEMATCH]).to eq "[]" expect("-@"[CodeObjects::METHODNAMEMATCH]).to eq "-@" expect("method?"[CodeObjects::METHODNAMEMATCH]).to eq "method?" expect("method!!"[CodeObjects::METHODNAMEMATCH]).to eq "method!" end end describe :METHODMATCH do it "matches a full class method path" do expect("method"[CodeObjects::METHODMATCH]).to eq "method" expect("A::B::C.method?"[CodeObjects::METHODMATCH]).to eq "A::B::C.method?" expect("A::B::C :: method"[CodeObjects::METHODMATCH]).to eq "A::B::C :: method" expect("SomeClass . method"[CodeObjects::METHODMATCH]).to eq "SomeClass . method" end it "matches self.method" do expect("self :: method!"[CodeObjects::METHODMATCH]).to eq "self :: method!" expect("self.is_a?"[CodeObjects::METHODMATCH]).to eq "self.is_a?" end end describe :BUILTIN_EXCEPTIONS do it "includes all base exceptions" do bad_names = [] silence_warnings do YARD::CodeObjects::BUILTIN_EXCEPTIONS.each do |name| begin bad_names << name unless eval(name) <= Exception rescue NameError nil # noop end end end expect(bad_names).to be_empty end end describe :BUILTIN_CLASSES do it "includes all base classes" do bad_names = [] silence_warnings do YARD::CodeObjects::BUILTIN_CLASSES.each do |name| begin bad_names << name unless eval(name).is_a?(Class) rescue NameError nil # noop end end end expect(bad_names).to be_empty end it "includes all exceptions" do YARD::CodeObjects::BUILTIN_EXCEPTIONS.each do |name| expect(YARD::CodeObjects::BUILTIN_CLASSES).to include(name) end end end describe :BUILTIN_ALL do it "includes classes, modules, and exceptions" do a = YARD::CodeObjects::BUILTIN_ALL b = YARD::CodeObjects::BUILTIN_CLASSES c = YARD::CodeObjects::BUILTIN_MODULES expect(a).to eq b + c end end describe :BUILTIN_MODULES do it "includes all base modules" do silence_warnings do YARD::CodeObjects::BUILTIN_MODULES.each do |name| next if YARD.ruby19? && ["Precision"].include?(name) expect(eval(name)).to be_instance_of(Module) end end end end end yard-0.9.12/spec/code_objects/module_object_spec.rb0000755000004100000410000001134713206751010022325 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.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 "lists all methods (including mixin methods) via #meths" do meths = @yard.meths expect(meths).to include(P("YARD#foo")) expect(meths).to include(P("YARD#foo2")) expect(meths).to include(P("YARD.bar")) expect(meths).to include(P("SomeMod#mixmethod")) expect(meths).to include(P("AnotherMod#fizz")) end it "allows :visibility to be set" do meths = @yard.meths(:visibility => :public) expect(meths).not_to include(P("YARD.bar")) meths = @yard.meths(:visibility => [:public, :private]) expect(meths).to include(P("YARD#foo")) expect(meths).to include(P("YARD.bar")) expect(meths).not_to include(P("YARD#foo2")) end it "only displays class methods for :scope => :class" do meths = @yard.meths(:scope => :class) expect(meths).not_to include(P("YARD#foo")) expect(meths).not_to include(P("YARD#foo2")) expect(meths).not_to include(P("SomeMod#mixmethod")) expect(meths).not_to include(P("SomeMod.baz")) expect(meths).not_to include(P("AnotherMod#fazz")) expect(meths).to include(P("YARD.bar")) expect(meths).to include(P("AnotherMod#fizz")) end it "only displays instance methods for :scope => :class" do meths = @yard.meths(:scope => :instance) expect(meths).to include(P("YARD#foo")) expect(meths).to include(P("YARD#foo2")) expect(meths).to include(P("SomeMod#mixmethod")) expect(meths).not_to include(P("YARD.bar")) expect(meths).not_to include(P("AnotherMod#fizz")) end it "allows :included to be set" do meths = @yard.meths(:included => false) expect(meths).not_to include(P("SomeMod#mixmethod")) expect(meths).not_to include(P("AnotherMod#fizz")) expect(meths).to include(P("YARD#foo")) expect(meths).to include(P("YARD#foo2")) expect(meths).to include(P("YARD.bar")) end it "chooses the method defined in the class over an included module" do meths = @yard.meths expect(meths).not_to include(P("SomeMod#xyz")) expect(meths).to include(P("YARD#xyz")) expect(meths).not_to include(P("AnotherMod#bar")) expect(meths).to include(P("YARD.bar")) meths = @other.meths expect(meths).to include(P("SomeMod#xyz")) meths = @another.meths expect(meths).to 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 "shows only itself for an inheritance tree without included modules" do expect(@mod1.inheritance_tree).to eq [@mod1] end it "shows proper inheritance tree when modules are included" do expect(@mod1.inheritance_tree(true)).to eq [@mod1, @mod2, @mod3, @mod4] end it "does not list inheritance tree of proxy objects in inheritance tree" do expect(@proxy).not_to receive(:inheritance_tree) expect(@mod5.instance_mixins).to eq [@proxy] end it "lists class mixins in inheritance tree" do mod = ModuleObject.new(:root, :ClassMethods) recvmod = ModuleObject.new(:root, :ReceivingModule) recvmod.class_mixins << mod expect(recvmod.inheritance_tree(true)).to eq [recvmod, mod] end end end yard-0.9.12/spec/code_objects/method_object_spec.rb0000755000004100000410000001357213206751010022322 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe YARD::CodeObjects::MethodObject do before do Registry.clear @yard = ModuleObject.new(:root, :YARD) end context "for an instance method in the root" do it "has a path of testing" do meth = MethodObject.new(:root, :testing) expect(meth.path).to eq "#testing" end end context "for an instance method in YARD" do it "has a path of YARD#testing" do meth = MethodObject.new(@yard, :testing) expect(meth.path).to eq "YARD#testing" end end context "for a class method in YARD" do it "has a path of YARD.testing" do meth = MethodObject.new(@yard, :testing, :class) expect(meth.path).to eq "YARD.testing" end end context "for a class method added to root namespace" do it "has a path of ::testing (note the ::)" do meth = MethodObject.new(:root, :testing, :class) expect(meth.path).to eq "::testing" end end it "exists in the registry after successful creation" do MethodObject.new(@yard, :something, :class) expect(Registry.at("YARD.something")).not_to be nil expect(Registry.at("YARD#something")).to be nil expect(Registry.at("YARD::something")).to be nil MethodObject.new(@yard, :somethingelse) expect(Registry.at("YARD#somethingelse")).not_to be nil end it "allows #scope to be changed after creation" do obj = MethodObject.new(@yard, :something, :class) expect(Registry.at("YARD.something")).not_to be nil obj.scope = :instance expect(Registry.at("YARD.something")).to be nil expect(Registry.at("YARD#something")).not_to be nil end it "creates object in :class scope if scope is :module" do obj = MethodObject.new(@yard, :module_func, :module) expect(obj.scope).to eq :class expect(obj.visibility).to eq :public expect(Registry.at('YARD.module_func')).not_to be nil end it "creates second private instance method if scope is :module" do MethodObject.new(@yard, :module_func, :module) obj = Registry.at('YARD#module_func') expect(obj).not_to be nil expect(obj.visibility).to eq :private expect(obj.scope).to eq :instance end it "yields block to second method if scope is :module" do MethodObject.new(@yard, :module_func, :module) do |o| o.docstring = 'foo' end expect(Registry.at('YARD.module_func').docstring).to eq 'foo' expect(Registry.at('YARD#module_func').docstring).to eq 'foo' end describe "#name" do it "shows a prefix for an instance method when prefix=true" do obj = MethodObject.new(nil, :something) expect(obj.name(true)).to eq "#something" end it "never shows a prefix for a class method" do obj = MethodObject.new(nil, :something, :class) expect(obj.name).to eq :something expect(obj.name(true)).to eq "something" end end describe "#is_attribute?" do it "only returns true if attribute is set in namespace for read/write" do obj = MethodObject.new(@yard, :foo) @yard.attributes[:instance][:foo] = {:read => obj, :write => nil} expect(obj.is_attribute?).to be true expect(MethodObject.new(@yard, :foo=).is_attribute?).to be false end end describe "#attr_info" do it "returns attribute info if namespace is available" do obj = MethodObject.new(@yard, :foo) @yard.attributes[:instance][:foo] = {:read => obj, :write => nil} expect(obj.attr_info).to eq @yard.attributes[:instance][:foo] end it "returns nil if namespace is proxy" do MethodObject.new(P(:ProxyClass), :foo) expect(MethodObject.new(@yard, :foo).attr_info).to eq nil end it "returns nil if meth is not an attribute" do expect(MethodObject.new(@yard, :notanattribute).attr_info).to eq nil end end describe "#writer?" do it "returns true if method is a writer attribute" do obj = MethodObject.new(@yard, :foo=) @yard.attributes[:instance][:foo] = {:read => nil, :write => obj} expect(obj.writer?).to be true expect(MethodObject.new(@yard, :NOTfoo=).writer?).to be false end end describe "#reader?" do it "returns true if method is a reader attribute" do obj = MethodObject.new(@yard, :foo) @yard.attributes[:instance][:foo] = {:read => obj, :write => nil} expect(obj.reader?).to be true expect(MethodObject.new(@yard, :NOTfoo).reader?).to be false end end describe "#constructor?" do before { @class = ClassObject.new(:root, :MyClass) } it "marks the #initialize method as constructor" do MethodObject.new(@class, :initialize) end it "does not mark Klass.initialize as constructor" do expect(MethodObject.new(@class, :initialize, :class).constructor?).to be false end it "does not mark module method #initialize as constructor" do expect(MethodObject.new(@yard, :initialize).constructor?).to be false end end describe "#overridden_method" do before { Registry.clear } it "returns 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 expect(Registry.at('B#foo').overridden_method).to eq Registry.at('C#foo') end it "returns overridden method from superclass" do YARD.parse_string(<<-eof) class A; def foo; end end class B < A; def foo; end end eof expect(Registry.at('B#foo').overridden_method).to eq Registry.at('A#foo') end it "returns nil if none is found" do YARD.parse_string(<<-eof) class A; end class B < A; def foo; end end eof expect(Registry.at('B#foo').overridden_method).to be nil end it "returns nil if namespace is a proxy" do YARD.parse_string "def ARGV.foo; end" expect(Registry.at('ARGV.foo').overridden_method).to be nil end end end yard-0.9.12/spec/code_objects/code_object_list_spec.rb0000755000004100000410000000163013206751010022777 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe YARD::CodeObjects::CodeObjectList do before { Registry.clear } describe "#push" do it "only allows CodeObjects::Base, String or Symbol" do list = CodeObjectList.new(nil) expect { list.push(:hash => 1) }.to raise_error(ArgumentError) list << "Test" list << :Test2 list << ModuleObject.new(nil, :YARD) expect(list.size).to eq 3 end end it "added value should be a proxy if parameter was String or Symbol" do list = CodeObjectList.new(nil) list << "Test" expect(list.first.class).to eq Proxy end it "contains a unique list of objects" do obj = ModuleObject.new(nil, :YARD) list = CodeObjectList.new(nil) list << P(:YARD) list << obj expect(list.size).to eq 1 list << :Test list << "Test" expect(list.size).to eq 2 end end yard-0.9.12/spec/code_objects/base_spec.rb0000755000004100000410000003615313206751010020426 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe YARD::CodeObjects::Base do before { Registry.clear } it "does not allow empty object name" do expect { Base.new(:root, '') }.to raise_error(ArgumentError) end it "returns a unique instance of any registered object" do obj = ClassObject.new(:root, :Me) obj2 = ClassObject.new(:root, :Me) expect(obj.object_id).to eq obj2.object_id obj3 = ModuleObject.new(obj, :Too) obj4 = CodeObjects::Base.new(obj3, :Hello) obj4.parent = obj obj5 = CodeObjects::Base.new(obj3, :hello) expect(obj4.object_id).not_to eq obj5.object_id end it "creates a new object if cached object is not of the same class" do expect(ConstantObject.new(:root, "MYMODULE")).to be_instance_of(ConstantObject) expect(ModuleObject.new(:root, "MYMODULE")).to be_instance_of(ModuleObject) expect(ClassObject.new(:root, "MYMODULE")).to be_instance_of(ClassObject) expect(YARD::Registry.at("MYMODULE")).to be_instance_of(ClassObject) end it "simplifies complex namespace paths" do obj = ClassObject.new(:root, "A::B::C::D") expect(obj.name).to eq :D expect(obj.path).to eq "A::B::C::D" expect(obj.namespace).to eq P("A::B::C") end # @bug gh-552 it "simplifies complex namespace paths when path starts with ::" do obj = ClassObject.new(:root, "::A::B::C::D") expect(obj.name).to eq :D expect(obj.path).to eq "A::B::C::D" expect(obj.namespace).to eq P("A::B::C") end it "calls the block again 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 expect(o1.object_id).to eq o2.object_id expect(o1.docstring).to eq "NOT_DOCSTRING" expect(o2.docstring).to eq "NOT_DOCSTRING" end it "allows complex name and converts it to namespace" do obj = CodeObjects::Base.new(nil, "A::B") expect(obj.namespace.path).to eq "A" expect(obj.name).to eq :B end it "allows namespace to be nil and not register in the Registry" do obj = CodeObjects::Base.new(nil, :Me) expect(obj.namespace).to eq nil expect(Registry.at(:Me)).to eq nil end it "allows namespace to be a NamespaceObject" do ns = ModuleObject.new(:root, :Name) obj = CodeObjects::Base.new(ns, :Me) expect(obj.namespace).to eq ns end it "allows :root to be the shorthand namespace of `Registry.root`" do obj = CodeObjects::Base.new(:root, :Me) expect(obj.namespace).to eq Registry.root end it "does not allow any other types as namespace" do expect { CodeObjects::Base.new("ROOT!", :Me) }.to raise_error(ArgumentError) end it "registers itself in the registry if namespace is supplied" do obj = ModuleObject.new(:root, :Me) expect(Registry.at(:Me)).to eq obj obj2 = ModuleObject.new(obj, :Too) expect(Registry.at(:"Me::Too")).to eq obj2 end describe "#[]=" do it "sets any attribute" do obj = ModuleObject.new(:root, :YARD) obj[:some_attr] = "hello" expect(obj[:some_attr]).to eq "hello" end it "uses the accessor method if available" do obj = CodeObjects::Base.new(:root, :YARD) obj[:source] = "hello" expect(obj.source).to eq "hello" obj.source = "unhello" expect(obj[:source]).to eq "unhello" end end it "sets attributes via attr= through method_missing" do obj = CodeObjects::Base.new(:root, :YARD) obj.something = 2 expect(obj.something).to eq 2 expect(obj[:something]).to eq 2 end it "exists in the parent's #children after creation" do obj = ModuleObject.new(:root, :YARD) obj2 = MethodObject.new(obj, :testing) expect(obj.children).to include(obj2) end it "properly re-indents 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 expect(obj.source).to eq "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 expect(Registry.at('#key?').source).to eq "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 expect(Registry.at('#key?').source).to eq "def key?(key)\n if x == 2\n puts key\n else\n exit\n end\nend" end it "does 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 expect(Registry.at('XYZ::ZYX::ABC#msg').source).to eq "def msg\n hello_world\nend" end it "handles source for 'def x; end'" do Registry.clear Parser::SourceParser.parse_string "def x; 2 end" expect(Registry.at('#x').source).to eq "def x; 2 end" end it "sets file and line information" do Parser::SourceParser.parse_string <<-eof class X; end eof expect(Registry.at(:X).file).to eq '(stdin)' expect(Registry.at(:X).line).to eq 1 end it "maintains 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 expect(Registry.at(:X).file).to eq '(stdin)' expect(Registry.at(:X).line).to eq 1 expect(Registry.at(:X).files).to eq [['(stdin)', 1], ['(stdin)', 2], ['(stdin)', 3]] end it "maintains all file associations when objects are defined multiple times in multiple files" do 3.times do |i| allow(File).to receive(:read_binary).and_return("class X; end") Parser::SourceParser.new.parse("file#{i + 1}.rb") end expect(Registry.at(:X).file).to eq 'file1.rb' expect(Registry.at(:X).line).to eq 1 expect(Registry.at(:X).files).to eq [['file1.rb', 1], ['file2.rb', 1], ['file3.rb', 1]] end it "prioritizes 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 expect(Registry.at(:X).file).to eq '(stdin)' expect(Registry.at(:X).line).to eq 4 expect(Registry.at(:X).files).to eq [['(stdin)', 4], ['(stdin)', 1], ['(stdin)', 2]] end describe "#format" do it "sends object to Templates.render" do object = MethodObject.new(:root, :method) expect(Templates::Engine).to receive(:render).with(:x => 1, :object => object, :type => object.type) object.format :x => 1 end it "does not change options object class" do opts = YARD::Templates::TemplateOptions.new opts.type = "test" object = MethodObject.new(:root, :method) expect(Templates::Engine).to receive(:render).with kind_of(YARD::Templates::TemplateOptions) object.format(opts) end end describe "#source_type" do it "defaults to :ruby" do object = MethodObject.new(:root, :method) expect(object.source_type).to eq :ruby end end describe "#relative_path" do it "accepts a string" do YARD.parse_string "module A; class B; end; class C; end; end" expect(Registry.at('A::B').relative_path(Registry.at('A::C'))).to eq( Registry.at('A::B').relative_path('A::C') ) end it "returns full class name when objects share a common class prefix" do YARD.parse_string "module User; end; module UserManager; end" expect(Registry.at('User').relative_path('UserManager')).to eq 'UserManager' expect(Registry.at('User').relative_path(Registry.at('UserManager'))).to eq 'UserManager' end it "returns the relative path when they share a common namespace" do YARD.parse_string "module A; class B; end; class C; end; end" expect(Registry.at('A::B').relative_path(Registry.at('A::C'))).to eq 'C' YARD.parse_string "module Foo; module A; end; module B; def foo; end end end" expect(Registry.at('Foo::A').relative_path(Registry.at('Foo::B#foo'))).to eq 'B#foo' end it "returns 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" expect(Registry.at('A::B').relative_path('D::C')).to eq 'D::C' YARD.parse_string 'module C::B::C; module Apple; end; module Ant; end end' expect(Registry.at('C::B::C::Apple').relative_path('C::B::C::Ant')).to eq 'Ant' YARD.parse_string 'module OMG::ABC; end; class Object; end' expect(Registry.at('OMG::ABC').relative_path('Object')).to eq "Object" YARD.parse_string("class YARD::Config; MYCONST = 1; end") expect(Registry.at('YARD::Config').relative_path('YARD::Config::MYCONST')).to eq "MYCONST" end it "returns a relative path for class methods" do YARD.parse_string "module A; def self.b; end; def self.c; end; end" expect(Registry.at('A.b').relative_path('A.c')).to eq 'c' expect(Registry.at('A').relative_path('A.c')).to eq 'c' end it "returns a relative path for instance methods" do YARD.parse_string "module A; def b; end; def c; end; end" expect(Registry.at('A#b').relative_path('A#c')).to eq '#c' expect(Registry.at('A').relative_path('A#c')).to eq '#c' end it "returns full path if relative path is to parent namespace" do YARD.parse_string "module A; module B; end end" expect(Registry.at('A::B').relative_path('A')).to eq 'A' end it "only returns name for relative path to self" do YARD.parse_string("class A::B::C; def foo; end end") expect(Registry.at('A::B::C').relative_path('A::B::C')).to eq 'C' expect(Registry.at('A::B::C#foo').relative_path('A::B::C#foo')).to eq '#foo' end end describe "#docstring=" do it "converts string into Docstring when #docstring= is set" do o = ClassObject.new(:root, :Me) o.docstring = "DOCSTRING" expect(o.docstring).to be_instance_of(Docstring) end it "sets 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)' expect(o.docstring).to eq "FOO" end it "does not copy docstring mid-docstring" do doc = "Hello.\n(see file.rb)\nmore documentation" o = ClassObject.new(:root, :Me) o.docstring = doc expect(o.docstring).to eq doc end it "allows 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) expect(o.docstring).to eq "FOO\n\nEXTRA" expect(o.docstring).to have_tag(:api) end end describe "#docstring" do it "returns an empty string if docstring was '(see Path)' and Path is not resolved" do o = ClassObject.new(:root, :Me) o.docstring = '(see AnotherObject)' expect(o.docstring).to eq "" end it "returns docstring when object is resolved" do o = ClassObject.new(:root, :Me) o.docstring = '(see AnotherObject)' expect(o.docstring).to eq "" ClassObject.new(:root, :AnotherObject) {|x| x.docstring = "FOO" } expect(o.docstring).to eq "FOO" end describe "localization" do it "returns localized docstring" do fr_locale = YARD::I18n::Locale.new('fr') allow(fr_locale).to receive(:translate).with('Hello').and_return('Bonjour') o = ClassObject.new(:root, :Me) o.docstring = 'Hello' expect(o.docstring).to eq 'Hello' allow(Registry).to receive(:locale).with('fr').and_return(fr_locale) expect(o.docstring('fr')).to eq "Bonjour" end it "returns updated localized docstring" do fr_locale = YARD::I18n::Locale.new('fr') allow(Registry).to receive(:locale).with('fr').and_return(fr_locale) o = ClassObject.new(:root, :Me) o.docstring = 'Hello' expect(o.docstring).to eq 'Hello' allow(fr_locale).to receive(:translate).with('Hello').and_return('Bonjour') expect(o.docstring('fr')).to eq "Bonjour" o.docstring = 'World' allow(fr_locale).to receive(:translate).with('World').and_return('Monde') expect(o.docstring('fr')).to eq "Monde" expect(o.docstring).to eq 'World' end end end describe "#add_file" do it "only adds a file/line combination once" do o = ClassObject.new(:root, :Me) o.add_file('filename', 12) expect(o.files).to eq [['filename', 12]] o.add_file('filename', 12) expect(o.files).to eq [['filename', 12]] o.add_file('filename', 40) # different line expect(o.files).to eq [['filename', 12], ['filename', 40]] end end describe "#copy_to" do it "copies 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) expect(foo_c.scope).to eq :class expect(foo_c.visibility).to eq :private expect(foo_c.type).to eq :method expect(foo_c.class).to eq MethodObject expect(foo_c.path).to eq '::foo' expect(foo_c.docstring).to eq "A docstring" expect(foo_c.tag(:return).types).to eq ['String'] expect(foo_c.file).to eq '(stdin)' expect(foo_c.line).to eq 4 expect(foo_c.source).to match(/source_code_here/) expect(foo_c.signature).to eq 'def foo(a, b, c)' expect(foo_c.parameters).to eq [['a', nil], ['b', nil], ['c', nil]] end it "returns the copied object" do YARD.parse_string 'def foo; end' foo_c = MethodObject.new(:root, :foo, :class) expect(Registry.at('#foo').copy_to(foo_c)).to eq foo_c end it "copies docstring and rewrite tags to 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) expect(foo_i.tags).not_to eq foo_c.tags expect(foo_c.tags.first.object).to eq foo_c end it "only copies #copyable_attributes" do foo = MethodObject.new(:root, :foo) expect(foo).to receive(:copyable_attributes).and_return %w(a b c) expect(foo).to receive(:instance_variable_get).with('@a').and_return(1) expect(foo).to receive(:instance_variable_get).with('@b').and_return(2) expect(foo).to receive(:instance_variable_get).with('@c').and_return(3) bar = MethodObject.new(:root, :bar) expect(bar).to receive(:instance_variable_set).with('@a', 1) expect(bar).to receive(:instance_variable_set).with('@b', 2) expect(bar).to receive(:instance_variable_set).with('@c', 3) foo.copy_to(bar) end end end yard-0.9.12/spec/code_objects/macro_object_spec.rb0000755000004100000410000001025213206751010022133 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe YARD::CodeObjects::MacroObject do before do Registry.clear end describe ".create" do def create(*args) MacroObject.create(*args) end it "creates an object" do create('foo', '') obj = Registry.at('.macro.foo') expect(obj).not_to be nil end it "uses identity map" do obj1 = create('foo', '') obj2 = create('foo', '') expect(obj1.object_id).to eq obj2.object_id end it "allows specifying of macro data" do obj = create('foo', 'MACRODATA') expect(obj.macro_data).to eq 'MACRODATA' end context "if a method object is provided" do it "attaches it" do obj = create('foo', 'MACRODATA', P('Foo.property')) expect(obj.method_object).to eq P('Foo.property') expect(obj).to be_attached end end end describe ".find" do before { MacroObject.create('foo', 'DATA') } it "searches for an object by name" do expect(MacroObject.find('foo').macro_data).to eq 'DATA' end it "accepts Symbol" do expect(MacroObject.find(:foo).macro_data).to eq 'DATA' end end describe ".find_or_create" do it "looks up name if @!macro is present and find object" do macro1 = MacroObject.create('foo', 'FOO') macro2 = MacroObject.find_or_create('foo', "a b c") expect(macro1).to eq macro2 end it "creates new macro if macro by that name does not exist" do MacroObject.find_or_create('foo', "@!method $1") expect(MacroObject.find('foo').macro_data).to eq "@!method $1" end end describe ".apply" do let(:args) { %w(foo a b c) } def apply(comments) MacroObject.apply(comments, args) end it "only expands macros if @macro is present" do expect(apply("$1$2$3")).to eq "$1$2$3" end it "handles macro text inside block" do expect(apply("@!macro\n foo$1$2$3\nfoobaz")).to eq "fooabc\nfoobaz" end it "appends docstring to existing macro" do MacroObject.create('name', '$3$2$1') result = MacroObject.apply("@!macro name\nfoobar", args) expect(result).to eq "cba\nfoobar" end it "uses 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') expect(result).to eq "cba\nEXTRA" expect(MacroObject.apply("@!macro name\nFOO", args)).to eq "cba\nFOO" end it "creates macros if they don't exist" do result = MacroObject.apply("@!macro name\n foo!$1", args, 'SOURCE') expect(result).to eq "foo!a" expect(MacroObject.find('name').macro_data).to eq 'foo!$1' end it "keeps other tags" do expect(apply("@!macro\n foo$1$2$3\n@param name foo\nfoo")).to eq( "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 "allows escaping of macro syntax" do expect(expand("$1\\$2$3")).to eq "a$2c" end it "replaces $* with the whole statement" do expect(expand("$* ${*}")).to eq "foo :bar, :baz foo :bar, :baz" end it "replaces $0 with method name" do expect(expand("$0 ${0}")).to eq "foo foo" end it "replaces all $N values with the Nth argument in the method call" do expect(expand("$1$2$3${3}\nfoobar")).to eq "abcc\nfoobar" end it "replaces ${N-M} ranges with N-M arguments (incl. commas)" do expect(expand("${1-2}x")).to eq "a, bx" end it "handles open ended ranges (${N-})" do expect(expand("${2-}")).to eq "b, c" end it "handles negative indexes ($-N)" do expect(expand("$-1 ${-2-} ${-2--2}")).to eq "c b, c b" end it "accepts Docstring objects" do expect(expand(Docstring.new("$1\n@param name foo"))).to eq "a\n@param name foo" end end describe "#expand" do it "expands a macro given its data" do macro = MacroObject.create_docstring('foo', '$1 $2 THREE!') expect(macro.expand(['NAME', 'ONE', 'TWO'])).to eq "ONE TWO THREE!" end end end yard-0.9.12/spec/code_objects/namespace_object_spec.rb0000755000004100000410000001272613206751010022776 0ustar www-datawww-data# frozen_string_literal: true require File.dirname(__FILE__) + '/spec_helper' RSpec.describe YARD::CodeObjects::NamespaceObject do before { Registry.clear } describe "#child" do it "returns the object matching the name passed in if argument is a Symbol" do obj = NamespaceObject.new(nil, :YARD) other = NamespaceObject.new(obj, :Other) expect(obj.child(:Other)).to eq other expect(obj.child('Other')).to eq other end it "looks 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 expect(obj.child(:somevalue => 2)).to eq other end end describe "#meths" do it "returns #meths even if parent is a Proxy" do obj = NamespaceObject.new(P(:String), :YARD) expect(obj.meths).to be_empty end it "does 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 expect(meths).to include(bmeth) expect(meths).to include(cmeth) expect(meths).to include(cmeth2) expect(meths).not_to include(ameth) meths = c.included_meths expect(meths).to include(bmeth) expect(meths).not_to include(ameth) expect(meths).not_to include(cmeth) expect(meths).not_to include(cmeth2) end end describe "#included_meths" do it "lists 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| expect(o.scope).to eq :instance } meths = c.included_meths(:scope => :class) meths.each {|o| expect(o.scope).to eq :class } end it "does 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) expect(meths).not_to include(ameth) expect(meths).to include(bmeth) meths = c.included_meths(:scope => :class) expect(meths).to include(ameth) expect(meths).not_to include(bmeth) end end describe "#class_attributes" do it "lists 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} expect(a.class_attributes.keys).to include(:a) expect(a.class_attributes.keys).not_to include(:b) end end describe "#instance_attributes" do it "lists 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} expect(a.instance_attributes.keys).to include(:a) expect(a.instance_attributes.keys).to 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 "lists all included constants by default" do consts = P(:C).constants expect(consts).to include(P('A::CONST1')) expect(consts).to include(P('C::CONST4')) end it "allows :included to be set to false to ignore included constants" do consts = P(:C).constants(:included => false) expect(consts).not_to include(P('A::CONST1')) expect(consts).to include(P('C::CONST4')) end it "does not list an included constant if it is defined in the object" do consts = P(:C).constants expect(consts).to include(P('C::CONST3')) expect(consts).not_to include(P('B::CONST3')) end it "does not list an included constant if it is shadowed by another included constant" do consts = P(:C).included_constants expect(consts).to include(P('B::CONST2')) expect(consts).not_to include(P('A::CONST2')) end end describe "#included_meths" do it "returns 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 expect(Registry.at('A').included_meths(:all => true)).to eq [P('C#bar'), P('B#foo')] end end end yard-0.9.12/spec/registry_store_spec.rb0000755000004100000410000003055113206751010020151 0ustar www-datawww-data# frozen_string_literal: true RSpec.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) allow(Serializers::YardocSerializer).to receive(:new).and_return(@serializer) end describe "#load" do it "loads root.dat as full object list if it is a Hash" do expect(File).to receive(:directory?).with('foo').and_return(true) expect(File).to receive(:file?).with('foo/checksums').and_return(false) expect(File).to receive(:file?).with('foo/proxy_types').and_return(false) expect(File).to receive(:file?).with('foo/object_types').and_return(false) expect(@serializer).to receive(:deserialize).with('root').and_return(:root => @foo, :A => @bar) expect(@store.load('foo')).to be true expect(@store.root).to eq @foo expect(@store.get('A')).to eq @bar end it "loads old yardoc format if .yardoc is a file" do expect(File).to receive(:directory?).with('foo').and_return(false) expect(File).to receive(:file?).with('foo').and_return(true) expect(File).to receive(:read_binary).with('foo').and_return('FOO') expect(Marshal).to receive(:load).with('FOO') @store.load('foo') end it "loads new yardoc format if .yardoc is a directory" do expect(File).to receive(:directory?).with('foo').and_return(true) expect(File).to receive(:file?).with('foo/checksums').and_return(false) expect(File).to receive(:file?).with('foo/proxy_types').and_return(false) expect(File).to receive(:file?).with('foo/object_types').and_return(false) expect(File).to receive(:file?).with('foo/objects/root.dat').and_return(false) expect(@store.load('foo')).to be true end it "returns true if .yardoc is loaded (file)" do expect(File).to receive(:directory?).with('myyardoc').and_return(false) expect(File).to receive(:file?).with('myyardoc').and_return(true) expect(File).to receive(:read_binary).with('myyardoc').and_return(Marshal.dump('')) expect(@store.load('myyardoc')).to be true end it "returns true if .yardoc is loaded (directory)" do expect(File).to receive(:directory?).with('foo').and_return(true) expect(File).to receive(:file?).with('foo/checksums').and_return(false) expect(File).to receive(:file?).with('foo/proxy_types').and_return(false) expect(File).to receive(:file?).with('foo/object_types').and_return(false) expect(File).to receive(:file?).with('foo/objects/root.dat').and_return(false) expect(@store.load('foo')).to be true end it "returns false if .yardoc does not exist" do expect(@store.load('NONEXIST')).to be false end it "returns false if there is no file to load" do expect(@store.load(nil)).to be false end it "loads checksums if they exist" do expect(File).to receive(:directory?).with('foo').and_return(true) expect(File).to receive(:file?).with('foo/checksums').and_return(true) expect(File).to receive(:file?).with('foo/proxy_types').and_return(false) expect(File).to receive(:file?).with('foo/objects/root.dat').and_return(false) expect(File).to receive(:file?).with('foo/object_types').and_return(false) expect(File).to receive(:readlines).with('foo/checksums').and_return([ 'file1 CHECKSUM1', ' file2 CHECKSUM2 ' ]) expect(@store.load('foo')).to be true expect(@store.checksums).to eq('file1' => 'CHECKSUM1', 'file2' => 'CHECKSUM2') end it "loads proxy_types if they exist" do expect(File).to receive(:directory?).with('foo').and_return(true) expect(File).to receive(:file?).with('foo/checksums').and_return(false) expect(File).to receive(:file?).with('foo/proxy_types').and_return(true) expect(File).to receive(:file?).with('foo/object_types').and_return(false) expect(File).to receive(:file?).with('foo/objects/root.dat').and_return(false) expect(File).to receive(:read_binary).with('foo/proxy_types').and_return(Marshal.dump('a' => 'b')) expect(@store.load('foo')).to be true expect(@store.proxy_types).to eq('a' => 'b') end it "loads root object if it exists" do expect(File).to receive(:directory?).with('foo').and_return(true) expect(File).to receive(:file?).with('foo/checksums').and_return(false) expect(File).to receive(:file?).with('foo/proxy_types').and_return(false) expect(File).to receive(:file?).with('foo/object_types').and_return(false) expect(File).to receive(:file?).with('foo/objects/root.dat').and_return(true) expect(File).to receive(:read_binary).with('foo/objects/root.dat').and_return(Marshal.dump(@foo)) expect(@store.load('foo')).to be true expect(@store.root).to eq @foo end end describe "#save" do before do allow(@store).to receive(:write_proxy_types) allow(@store).to receive(:write_checksums) allow(@store).to receive(:destroy) end after do Registry.single_object_db = nil end def saves_to_singledb expect(@serializer).to 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 expect(@serializer).to receive(:serialize).exactly(times).times @store.save(true, 'foo') @last = times end it "saves 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 expect(@serializer.complete?).to eq true end it "saves 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 "saves 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 "never saves 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 "assigns values" do @store.put(:YARD, @foo) expect(@store.get(:YARD)).to eq @foo end it "treats '' as root" do @store.put('', @foo) expect(@store.get(:root)).to eq @foo end end describe "#get" do it "hits cache if object exists" do @store.put(:YARD, @foo) expect(@store.get(:YARD)).to eq @foo end it "hits backstore on cache miss and cache is not fully loaded" do serializer = double(:serializer) expect(serializer).to 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) expect(@store.get(:YARD)).to eq @foo expect(@store.get(:YARD)).to eq @foo expect(@store.instance_variable_get("@loaded_objects")).to eq 1 end end [:keys, :values].each do |item| describe "##{item}" do it "loads entire database if reload=true" do expect(File).to receive(:directory?).with('foo').and_return(true) @store.load('foo') expect(@store).to receive(:load_all) @store.send(item, true) end it "does not load entire database if reload=false" do expect(File).to receive(:directory?).with('foo').and_return(true) @store.load('foo') expect(@store).not_to receive(:load_all) @store.send(item, false) end end end describe "#paths_for_type" do after { Registry.clear } it "sets all object types if not set by object_types" do expect(File).to receive(:directory?).with('foo').and_return(true) expect(File).to receive(:file?).with('foo/checksums').and_return(false) expect(File).to receive(:file?).with('foo/proxy_types').and_return(false) expect(File).to receive(:file?).with('foo/object_types').and_return(false) expect(@serializer).to receive(:deserialize).with('root').and_return(:'A#foo' => @foo, :A => @bar) @store.load('foo') expect(@store.paths_for_type(:method)).to eq ['#foo'] expect(@store.paths_for_type(:class)).to eq ['Bar'] end it "keeps track of types when assigning values" do @store.put(:abc, @foo) expect(@store.paths_for_type(@foo.type)).to eq ['abc'] end it "reassigns path if type changes" do foo = CodeObjects::ClassObject.new(:root, :Foo) @store.put('Foo', foo) expect(@store.get('Foo').type).to eq :class expect(@store.paths_for_type(:class)).to eq ["Foo"] foo = CodeObjects::ModuleObject.new(:root, :Foo) @store.put('Foo', foo) expect(@store.get('Foo').type).to eq :module expect(@store.paths_for_type(:class)).to eq [] expect(@store.paths_for_type(:module)).to eq ["Foo"] end end describe "#values_for_type" do it "returns all objects with type" do @store.put(:abc, @foo) expect(@store.values_for_type(@foo.type)).to eq [@foo] end end describe "#load_all" do it "loads the entire database" do foomock = double(:Foo) barmock = double(:Bar) allow(foomock).to receive(:type).and_return(:class) allow(barmock).to receive(:type).and_return(:class) expect(foomock).to receive(:path).and_return('Foo') expect(barmock).to receive(:path).and_return('Bar') expect(File).to receive(:directory?).with('foo').and_return(true) expect(File).to receive(:file?).with('foo/proxy_types').and_return(false) expect(File).to receive(:file?).with('foo/object_types').and_return(false) expect(File).to receive(:file?).with('foo/checksums').and_return(false) expect(File).to receive(:file?).with('foo/objects/root.dat').and_return(false) expect(@store).to 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") expect(serializer).to receive(:deserialize).with('foo/objects/foo', true).and_return(foomock) expect(serializer).to receive(:deserialize).with('foo/objects/bar', true).and_return(barmock) @store.send(:load_all) expect(@store.instance_variable_get("@available_objects")).to eq 2 expect(@store.instance_variable_get("@loaded_objects")).to eq 2 expect(@store[:Foo]).to eq foomock expect(@store[:Bar]).to eq barmock end end describe "#destroy" do it "destroys file ending in .yardoc when force=false" do expect(File).to receive(:file?).with('foo.yardoc').and_return(true) expect(File).to receive(:unlink).with('foo.yardoc') @store.instance_variable_set("@file", 'foo.yardoc') expect(@store.destroy).to be true end it "destroys dir ending in .yardoc when force=false" do expect(File).to receive(:directory?).with('foo.yardoc').and_return(true) expect(FileUtils).to receive(:rm_rf).with('foo.yardoc') @store.instance_variable_set("@file", 'foo.yardoc') expect(@store.destroy).to be true end it "does not destroy file/dir not ending in .yardoc when force=false" do expect(File).not_to receive(:file?).with('foo') expect(File).not_to receive(:directory?).with('foo') expect(File).not_to receive(:unlink).with('foo') expect(FileUtils).not_to receive(:rm_rf).with('foo') @store.instance_variable_set("@file", 'foo') expect(@store.destroy).to be false end it "destroys any file/dir when force=true" do expect(File).to receive(:file?).with('foo').and_return(true) expect(File).to receive(:unlink).with('foo') @store.instance_variable_set("@file", 'foo') expect(@store.destroy(true)).to be true end end describe "#locale" do it "loads ./po/LOCALE_NAME.po" do fr_locale = I18n::Locale.new("fr") expect(I18n::Locale).to receive(:new).with("fr").and_return(fr_locale) expect(Registry).to receive(:po_dir).and_return("po") expect(fr_locale).to receive(:load).with("po") expect(@store.locale("fr")).to eq fr_locale end end end yard-0.9.12/spec/registry_spec.rb0000755000004100000410000004216413206751010016740 0ustar www-datawww-data# frozen_string_literal: true include CodeObjects require "thread" RSpec.describe YARD::Registry do before { Registry.clear } describe ".yardoc_file_for_gem" do before do @gem = double('gem') allow(@gem).to receive(:name).and_return('foo') allow(@gem).to receive(:full_name).and_return('foo-1.0') allow(@gem).to receive(:full_gem_path).and_return('/path/to/foo') allow(@gem).to receive(:doc_dir).and_return('/path/to/foo/doc') allow(@gem).to receive(:doc_dir).with('.yardoc').and_return('/path/to/foo/doc/.yardoc') end it "returns nil if gem isn't found" do allow(YARD::GemIndex).to receive(:find_all_by_name).with('foo', '>= 0').and_return([]) expect(Registry.yardoc_file_for_gem('foo')).to eq nil end it "allows version to be specified" do allow(YARD::GemIndex).to receive(:find_all_by_name).with('foo', '= 2').and_return([]) expect(Registry.yardoc_file_for_gem('foo', '= 2')).to eq nil end it "returns existing .yardoc path for gem when for_writing=false" do allow(File).to receive(:exist?).twice.and_return(false) allow(File).to receive(:exist?).with('/path/to/foo/.yardoc').and_return(true) allow(YARD::GemIndex).to receive(:find_all_by_name).with('foo', '>= 0').and_return([@gem]) expect(Registry.yardoc_file_for_gem('foo')).to eq '/path/to/foo/.yardoc' end it "returns new existing .yardoc path for gem when for_writing=false" do allow(File).to receive(:exist?).and_return(false) allow(File).to receive(:exist?).with('/path/to/foo/doc/.yardoc').and_return(true) allow(YARD::GemIndex).to receive(:find_all_by_name).with('foo', '>= 0').and_return([@gem]) expect(Registry.yardoc_file_for_gem('foo')).to eq '/path/to/foo/doc/.yardoc' end it "returns nil if no .yardoc path exists in gem when for_writing=false" do allow(File).to receive(:exist?).twice.and_return(false) allow(File).to receive(:exist?).with('/path/to/foo/.yardoc').and_return(false) allow(YARD::GemIndex).to receive(:find_all_by_name).with('foo', '>= 0').and_return([@gem]) expect(Registry.yardoc_file_for_gem('foo')).to eq nil end it "searches local gem path first if for_writing=false" do allow(File).to receive(:exist?).and_return(true) allow(YARD::GemIndex).to receive(:find_all_by_name).with('foo', '>= 0').and_return([@gem]) expect(Registry.yardoc_file_for_gem('foo')).to match %r{/.yard/gem_index/foo-1.0.yardoc$} end it "returns global .yardoc path for gem if for_writing=true and dir is writable" do allow(File).to receive(:exist?).and_return(false) allow(File).to receive(:directory?).with(@gem.doc_dir).and_return(true) allow(File).to receive(:writable?).with(@gem.doc_dir).and_return(false) allow(File).to receive(:writable?).with(@gem.full_gem_path).and_return(true) allow(YARD::GemIndex).to receive(:find_all_by_name).with('foo', '>= 0').and_return([@gem]) expect(Registry.yardoc_file_for_gem('foo', '>= 0', true)).to eq '/path/to/foo/.yardoc' end it "returns new global .yardoc path for gem if for_writing=true and dir is writable" do allow(File).to receive(:writable?).with(@gem.doc_dir).and_return(true) allow(YARD::GemIndex).to receive(:find_all_by_name).with('foo', '>= 0').and_return([@gem]) expect(Registry.yardoc_file_for_gem('foo', '>= 0', true)).to eq '/path/to/foo/doc/.yardoc' end it "returns new global .yardoc path for gem if for_writing=true and parent dir is writable (but dir does not exist)" do allow(File).to receive(:writable?).with(@gem.doc_dir).and_return(false) allow(File).to receive(:directory?).with(@gem.doc_dir).and_return(false) allow(File).to receive(:writable?).with(File.dirname(@gem.doc_dir)).and_return(true) allow(YARD::GemIndex).to receive(:find_all_by_name).with('foo', '>= 0').and_return([@gem]) expect(Registry.yardoc_file_for_gem('foo', '>= 0', true)).to eq '/path/to/foo/doc/.yardoc' end it "returns local .yardoc path for gem if for_writing=true and dir is not writable" do allow(File).to receive(:writable?).with(@gem.doc_dir).and_return(false) allow(File).to receive(:writable?).with(@gem.full_gem_path).and_return(false) allow(YARD::GemIndex).to receive(:find_all_by_name).with('foo', '>= 0').and_return([@gem]) expect(Registry.yardoc_file_for_gem('foo', '>= 0', true)).to match %r{/.yard/gem_index/foo-1.0.yardoc$} end it "returns gem path if gem starts with yard-doc- and for_writing=false" do allow(@gem).to receive(:name).and_return('yard-doc-core') allow(@gem).to receive(:full_name).and_return('yard-doc-core-1.0') allow(@gem).to receive(:full_gem_path).and_return('/path/to/yard-doc-core') allow(YARD::GemIndex).to receive(:find_all_by_name).with('yard-doc-core', '>= 0').and_return([@gem]) allow(File).to receive(:exist?).with('/path/to/yard-doc-core/.yardoc').and_return(true) expect(Registry.yardoc_file_for_gem('yard-doc-core')).to eq '/path/to/yard-doc-core/.yardoc' end it "returns nil if gem starts with yard-doc- and for_writing=true" do allow(@gem).to receive(:name).and_return('yard-doc-core') allow(@gem).to receive(:full_name).and_return('yard-doc-core-1.0') allow(@gem).to receive(:full_gem_path).and_return('/path/to/yard-doc-core') allow(YARD::GemIndex).to receive(:find_all_by_name).with('yard-doc-core', '>= 0').and_return([@gem]) allow(File).to receive(:exist?).with('/path/to/yard-doc-core/.yardoc').and_return(true) expect(Registry.yardoc_file_for_gem('yard-doc-core', '>= 0', true)).to eq nil end end describe ".root" do it "has an empty path for root" do expect(Registry.root.path).to eq "" end end describe ".locale" do it "loads locale object" do fr_locale = I18n::Locale.new("fr") store = Registry.send(:thread_local_store) expect(store).to receive(:locale).with("fr").and_return(fr_locale) expect(Registry.locale("fr")).to eq fr_locale end end describe ".resolve" do it "resolves any existing namespace" do o1 = ModuleObject.new(:root, :A) o2 = ModuleObject.new(o1, :B) o3 = ModuleObject.new(o2, :C) expect(Registry.resolve(o1, "B::C")).to eq o3 Registry.resolve(:root, "A::B::C") end it "resolves 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) expect(Registry.resolve(o3, "::A")).to eq o1 expect(Registry.resolve(o3, "::String", false, true)).to eq P(:String) end it "resolves 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) expect(Registry.resolve(o1, "B::C#methname")).to eq o4 expect(Registry.resolve(o2, "C#methname")).to eq o4 expect(Registry.resolve(o3, "#methname")).to eq o4 end it "resolves instance methods in the root without # prefix" do o = MethodObject.new(:root, :methname) expect(Registry.resolve(:root, 'methname')).to eq o end it "does lexical lookup on the initial namespace" do YARD.parse_string <<-eof module A module B; module C; end end module D; module E; end end end eof d = Registry.at('A::B::C') expect(Registry.resolve(d, 'D::E')).to eq Registry.at('A::D::E') end it "resolves 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) expect(Registry.resolve(yard, "#hello", false)).to be nil expect(Registry.resolve(yard, "#hello", true)).to eq imeth expect(Registry.resolve(yard, "class_hello", false)).to be nil expect(Registry.resolve(yard, "class_hello", true)).to eq cmeth end it "does not look at superclass proxies when inheritance = true" do YARD.parse_string "class A::B; end" expect(Registry.resolve(Registry.at('A::B'), "#bar", true)).to eq nil end it "resolves 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) expect(Registry.resolve(yard, "#hello", false)).to be nil expect(Registry.resolve(yard, "#hello", true)).to eq imeth expect(Registry.resolve(yard, "class_hello", false)).to be nil expect(Registry.resolve(yard, "class_hello", true)).to eq cmeth end it "resolves 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 expect(Registry.resolve(P('MyObject'), '#foo', true)).to eq P('Object#foo') end it "resolves 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 expect(Registry.resolve(P('MyObject'), '#foo', true)).to eq P('BasicObject#foo') end it "does not perform lexical lookup to resolve a method object by more than one namespace" do YARD.parse_string <<-eof module A def foo; end def self.bar; end module B; module C; end end end eof expect(Registry.resolve(P('A::B::C'), '#foo', true)).to be nil expect(Registry.resolve(P('A::B::C'), '.bar', true)).to be nil expect(Registry.resolve(P('A::B'), '#foo', true)).not_to be nil expect(Registry.resolve(P('A::B'), '.bar', true)).not_to be nil end it "does 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 expect(Registry.resolve(P('MyObject'), '#foo', true)).to be nil end it "performs lookups on each individual namespace when inheritance = true" do YARD.parse_string <<-eof module A module B; include A::D end module C; extend A::D end module D; def bar; end end end eof r = Registry.root expect(Registry.resolve(r, 'A::B#bar', true)).to eq Registry.at('A::D#bar') expect(Registry.resolve(r, 'A::C.bar', true)).to eq Registry.at('A::D#bar') end it "allows type=:typename to ensure resolved object is of a certain type" do YARD.parse_string "class Foo; end" expect(Registry.resolve(Registry.root, 'Foo')).to eq Registry.at('Foo') expect(Registry.resolve(Registry.root, 'Foo', false, false, :method)).to be nil end it "allows 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 expect(Registry.resolve(P('Foo'), 'Bar', false, false, :class)).to eq Registry.at('Foo::Bar') expect(Registry.resolve(P('Foo'), 'Bar', false, false, :method)).to eq( Registry.at('Foo.Bar') ) end it "returns proxy fallback with given type if supplied" do YARD.parse_string "module Foo; end" proxy = Registry.resolve(P('Foo'), 'Bar', false, true, :method) expect(proxy.type).to eq :method proxy = Registry.resolve(P('Qux'), 'Bar', false, true, :method) expect(proxy.type).to eq :method end it "does not return proxy on original namespace if path is anchored to root" do YARD.parse_string "module Foo; class Bar; def baz; end end end" proxy = Registry.resolve(P('Foo::Bar#baz'), '::Bar', true, true) expect(proxy.path).to eq('Bar') expect(proxy.namespace).to equal(Registry.root) expect(proxy.type).to eq(:proxy) end it "only checks 'Path' in lookup on root namespace" do expect(Registry).to receive(:at).once.with('Test').and_return(true) Registry.resolve(Registry.root, "Test") end it "does not perform lookup by joining namespace and name without separator" do yard = ClassObject.new(:root, :YARD) expect(Registry).not_to receive(:at).with('YARDB') Registry.resolve(yard, 'B') end end describe ".all" do it "returns 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) expect(r).to include(o1, o2) end it "returns code objects" do o1 = ModuleObject.new(:root, :A) o2 = ClassObject.new(:root, :B) MethodObject.new(:root, :testing) r = Registry.all.select {|t| NamespaceObject === t } expect(r).to include(o1, o2) end it "allows .all to omit list" do o1 = ModuleObject.new(:root, :A) o2 = ClassObject.new(:root, :B) r = Registry.all expect(r).to include(o1, o2) end end describe ".paths" do it "returns all object paths" do ModuleObject.new(:root, :A) ClassObject.new(:root, :B) expect(Registry.paths).to include('A', 'B') end end describe ".load_yardoc" do it "delegates load to RegistryStore" do store = RegistryStore.new expect(store).to receive(:load).with('foo') expect(RegistryStore).to receive(:new).and_return(store) Registry.yardoc_file = 'foo' Registry.load_yardoc end it "returns itself" do expect(Registry.load_yardoc).to eq Registry end it "maintains hash key equality on loaded objects" do Registry.clear Registry.load!(File.dirname(__FILE__) + '/serializers/data/serialized_yardoc') baz = Registry.at('Foo#baz') expect(Registry.at('Foo').aliases.keys).to include(baz) expect(Registry.at('Foo').aliases.key?(baz)).to be true end end ['load', 'load_all', 'load!'].each do |meth| describe('.' + meth) do it "returns itself" do expect(Registry.send(meth)).to eq 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 "iterates over .all" do items = [] Registry.each {|x| items << x.path } expect(items.sort).to eq ['#a', '#b', '#c'] end it "includes Enumerable and allow for find, select" do expect(Registry.find {|x| x.path == "#a" }).to be_a(CodeObjects::MethodObject) end end describe ".instance" do it "returns itself" do expect(Registry.instance).to eq Registry end end describe ".single_object_db" do it "defaults to nil" do expect(Registry.single_object_db).to eq nil Thread.new { expect(Registry.single_object_db).to eq nil }.join end end describe "Thread local" do it "maintains 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 } "barrier < 2, spinning" while barrier < 2 expect(Registry.at('Foo').docstring).to eq "docstring 1" end threads << Thread.new do Registry.clear YARD.parse_string "# docstring 2\nclass Foo; end" mutex.synchronize { barrier += 1 } "barrier < 2, spinning" while barrier < 2 expect(Registry.at('Foo').docstring).to eq "docstring 2" end threads.each(&:join) end it "allows setting of yardoc_file in separate threads" do barrier = 0 mutex = Mutex.new threads = [] threads << Thread.new do expect(Registry.yardoc_file).to eq '.yardoc' Registry.yardoc_file = 'foo' mutex.synchronize { barrier += 1 } "barrier = 1, spinning" while barrier == 1 expect(Registry.yardoc_file).to eq 'foo' end threads << Thread.new do "barrier = 0, spinning" while barrier == 0 expect(Registry.yardoc_file).to eq '.yardoc' mutex.synchronize { barrier += 1 } Registry.yardoc_file = 'foo2' end threads.each(&:join) Registry.yardoc_file = Registry::DEFAULT_YARDOC_FILE end it "automatically clears in new threads" do Thread.new { expect(Registry.all).to be_empty }.join end it "allows setting of po_dir in separate threads" do barrier = 0 mutex = Mutex.new threads = [] threads << Thread.new do expect(Registry.po_dir).to eq 'po' Registry.po_dir = 'locale' mutex.synchronize { barrier += 1 } "barrier = 1, spinning" while barrier == 1 expect(Registry.po_dir).to eq 'locale' end threads << Thread.new do "barrier = 0, spinning" while barrier == 0 expect(Registry.po_dir).to eq 'po' mutex.synchronize { barrier += 1 } Registry.po_dir = '.' end threads.each(&:join) Registry.po_dir = Registry::DEFAULT_PO_DIR end end end yard-0.9.12/spec/verifier_spec.rb0000755000004100000410000000606413206751010016702 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::Verifier do describe "#parse_expressions" do it "creates #__execute method" do v = Verifier.new("expr1") expect(v).to respond_to(:__execute) end it "parses @tagname into tag('tagname')" do obj = double(:object) expect(obj).to receive(:tag).with('return') Verifier.new('@return').call(obj) end it "parses @@tagname into object.tags('tagname')" do obj = double(:object) expect(obj).to receive(:tags).with('return') Verifier.new('@@return').call(obj) end it "allows namespaced tag using @{} syntax" do obj = double(:object) expect(obj).to receive(:tag).with('yard.return') Verifier.new('@{yard.return}').call(obj) end it "allows namespaced tags using @{} syntax" do obj = double(:object) expect(obj).to receive(:tags).with('yard.return') Verifier.new('@@{yard.return}').call(obj) end it "calls methods on tag object" do obj = double(:object) obj2 = double(:tag) expect(obj).to receive(:tag).with('return').and_return obj2 expect(obj2).to receive(:foo) Verifier.new('@return.foo').call(obj) end it "sends any missing methods to object" do obj = double(:object) expect(obj).to receive(:has_tag?).with('return') Verifier.new('has_tag?("return")').call(obj) end it "allows multiple expressions" do obj = double(:object) expect(obj).to receive(:tag).with('return').and_return(true) expect(obj).to receive(:tag).with('param').and_return(false) expect(Verifier.new('@return', '@param').call(obj)).to be false end end describe "#o" do it "aliases object to o" do obj = double(:object) expect(obj).to receive(:a).ordered Verifier.new('o.a').call(obj) end end describe "#call" do it "doubles a nonexistent tag so that exceptions are not raised" do obj = double(:object) expect(obj).to receive(:tag).and_return(nil) expect(Verifier.new('@return.text').call(obj)).to be false end it "does not fail if no expressions were added" do expect { Verifier.new.call(nil) }.not_to raise_error end it "always ignores proxy objects and return true" do v = Verifier.new('tag(:x)') expect { expect(v.call(P('foo'))).to be true }.not_to raise_error end end describe "#expressions" do it "maintains a list of all unparsed expressions" do expect(Verifier.new('@return.text', '@private').expressions).to eq ['@return.text', '@private'] end end describe "#expressions=" do it "recompiles expressions when attribute is modified" do obj = double(:object) expect(obj).to receive(:tag).with('return') v = Verifier.new v.expressions = ['@return'] v.call(obj) end end describe "#add_expressions" do it "adds new expressions and recompile" do obj = double(:object) expect(obj).to receive(:tag).with('return') v = Verifier.new v.add_expressions '@return' v.call(obj) end end end yard-0.9.12/spec/cli/0000755000004100000410000000000013206751010014266 5ustar www-datawww-datayard-0.9.12/spec/cli/command_parser_spec.rb0000755000004100000410000000235213206751010020624 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::CLI::CommandParser do describe "#run" do before do @cmd = CLI::CommandParser.new end it "shows help if --help is provided" do command = double(:command) expect(command).to receive(:run).with('--help') CLI::CommandParser.commands[:foo] = command @cmd.class.default_command = :foo @cmd.run(*%w(foo --help)) end it "uses default command if first argument is a switch" do command = double(:command) expect(command).to receive(:run).with('--a', 'b', 'c') CLI::CommandParser.commands[:foo] = command @cmd.class.default_command = :foo @cmd.run(*%w(--a b c)) end it "uses default command if no arguments are provided" do command = double(:command) expect(command).to receive(:run) CLI::CommandParser.commands[:foo] = command @cmd.class.default_command = :foo @cmd.run end it "lists commands if command is not found" do expect(@cmd).to receive(:list_commands) @cmd.run(*%w(unknown_command --args)) end it "lists commands if --help is provided as sole argument" do expect(@cmd).to receive(:list_commands) @cmd.run(*%w(--help)) end end end yard-0.9.12/spec/cli/server_spec.rb0000755000004100000410000002503713206751010017145 0ustar www-datawww-data# frozen_string_literal: true class Server::WebrickAdapter; def start; end end RSpec.describe YARD::CLI::Server do before do allow(CLI::Yardoc).to receive(:run) @no_verify_libraries = false @set_libraries = true @no_adapter_mock = false @libraries = {} @options = {:single_library => true, :caching => false} @server_options = {:Port => 8808} @adapter = double(:adapter, :setup => nil) new_cli end after(:all) do Server::Adapter.shutdown end def new_cli @cli = subject end def rack_required require 'rack' rescue LoadError pending "rack required for this test" end def bundler_required require 'bundler' rescue LoadError pending "bundler required for this test" 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) allow(File).to receive(:exist?).with(yfile).and_return(true) end end end unless @no_adapter_mock allow(@cli).to receive(:adapter).and_return(@adapter) expect(@adapter).to receive(:new). with(@libraries, @options, @server_options).and_return(@adapter) expect(@adapter).to receive(:start) end @cli.run(*args.flatten) assert_libraries @libraries, @cli.libraries end def assert_libraries(expected_libs, actual_libs) expect(actual_libs).to eq 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| expect(actual.send(m)).to eq expected.send(m) end end end end # Mocks the existence of a file. def mock_file(filename, content = nil) allow(File).to receive(:exist?).with(filename).and_return(true) allow(File).to receive(:read_binary).with(filename).and_return(content) if content filename_e = File.expand_path(filename) mock_file(filename_e) unless filename_e == filename end context 'when .yardopts file exists' do before :each do Registry.yardoc_file = Registry::DEFAULT_YARDOC_FILE allow(File).to receive(:exist?).with(%r{\.yardoc/complete$}).and_return(false) allow(Dir).to receive(:pwd).and_return('/path/to/bar') allow(Dir).to receive(:chdir).and_yield @name = 'bar' end it "uses .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, File.expand_path('/path/to/bar/.yardoc'))] @libraries.values[0][0].source_path = File.expand_path('/path/to/bar') run end it "uses the yardoc db location specified by .yardopts" do allow(File).to receive(:exist?).with(%r{/foo/complete$}).and_return(false) mock_file '/path/to/bar/.yardopts', '--db foo' @libraries[@name] = [Server::LibraryVersion.new(@name, nil, File.expand_path('/path/to/bar/foo'))] @libraries.values[0][0].source_path = File.expand_path('/path/to/bar') run end it "parses .yardopts when the library list is odd" do mock_file '/path/to/bar/.yardopts', '--db foo' @libraries['a'] = [Server::LibraryVersion.new('a', nil, File.expand_path('/path/to/bar/foo'))] @libraries.values[0][0].source_path = File.expand_path('/path/to/bar') run 'a' end end context "when .yardopts file doesn't exist" do before :each do allow(File).to receive(:exist?).with(%r{\.yardoc/complete$}).and_return(false) allow(File).to receive(:exist?).with(%r{^(.*[\\/])?\.yardopts$}).and_return(false) end it "defaults to .yardoc if no library is specified" do allow(Dir).to receive(:chdir).and_yield expect(Dir).to receive(:pwd).at_least(:once).and_return(File.expand_path('/path/to/foo')) @libraries['foo'] = [Server::LibraryVersion.new('foo', nil, File.expand_path('/path/to/foo/.yardoc'))] run end it "uses .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 "forces multi library if more than one library is listed" do allow(File).to receive(: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 "fails if specified directory does not exist" do @set_libraries = false allow(File).to receive(:exist?).with('b').and_return(false) expect(log).to receive(:warn).with(/Cannot find yardoc db for a: "b"/) run %w(a b) end end describe "General options" do before do allow(File).to receive(:exist?).with(%r{\.yardoc/complete$}).and_return(false) allow(File).to receive(:exist?).with(/\.yardopts$/).and_return(false) end it "accepts -m, --multi-library" do @options[:single_library] = false run '-m' run '--multi-library' end it "accepts -c, --cache" do @options[:caching] = true run '-c' run '--cache' end it "accepts -r, --reload" do @options[:incremental] = true run '-r' run '--reload' end it "accepts -d, --daemon" do @server_options[:daemonize] = true run '-d' run '--daemon' end it "accepts -B, --bind" do @server_options[:Host] = 'example.com' run '-B', 'example.com' run '--bind', 'example.com' end it "binds address with WebRick adapter" do @server_options[:Host] = 'example.com' run '-B', 'example.com', '-a', 'webrick' run '--bind', 'example.com', '-a', 'webrick' end it "binds address with Rack adapter" do @server_options[:Host] = 'example.com' run '-B', 'example.com', '-a', 'rack' run '--bind', 'example.com', '-a', 'rack' end it "accepts -p, --port" do @server_options[:Port] = 10 run '-p', '10' run '--port', '10' end it "accepts --docroot" do @server_options[:DocumentRoot] = Dir.pwd + '/__foo/bar' run '--docroot', '__foo/bar' end it "accepts -a webrick to create WEBrick adapter" do expect(@cli).to receive(:adapter=).with(YARD::Server::WebrickAdapter) run '-a', 'webrick' end it "accepts -a rack to create Rack adapter" do rack_required expect(@cli).to receive(:adapter=).with(YARD::Server::RackAdapter) run '-a', 'rack' end it "defaults to Rack adapter if exists on system" do rack_required expect(@cli).to receive(:require).with('rubygems').and_return(false) expect(@cli).to receive(:require).with('rack').and_return(true) expect(@cli).to receive(:adapter=).with(YARD::Server::RackAdapter) @cli.send(:select_adapter) end it "falls back to WEBrick adapter if Rack is not on system" do expect(@cli).to receive(:require).with('rubygems').and_return(false) expect(@cli).to receive(:require).with('rack').and_raise(LoadError) expect(@cli).to receive(:adapter=).with(YARD::Server::WebrickAdapter) @cli.send(:select_adapter) end it "accepts -s, --server" do @server_options[:server] = 'thin' run '-s', 'thin' run '--server', 'thin' end it "accepts -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 = double(:gem1, :name => 'gem1', :version => '1.0.0', :full_gem_path => '/path/to/foo') gem2 = double(:gem2, :name => 'gem2', :version => '1.0.0', :full_gem_path => '/path/to/bar') specs = {'gem1' => gem1, 'gem2' => gem2} allow(YARD::GemIndex).to receive(:find_all_by_name) do |k, _ver| specs.grep(k).map {|name| specs[name] } end allow(YARD::GemIndex).to receive(:each) {|&b| specs.values.each(&b) } run '-g' run '--gems' end it "accepts -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 = double(:gem1, :name => 'gem1', :version => '1.0.0', :full_gem_path => '/path/to/foo') gem2 = double(:gem2, :name => 'gem2', :version => '1.0.0', :full_gem_path => '/path/to/bar') lockfile_parser = double(:new, :specs => [gem1, gem2]) allow(Bundler::LockfileParser).to receive(:new).and_return(lockfile_parser) expect(File).to receive(:exist?).at_least(2).times.with("Gemfile.lock").and_return(true) allow(File).to receive(:read) run '-G' run '--gemfile' expect(File).to receive(:exist?).with("different_name.lock").and_return(true) run '--gemfile', 'different_name' end it "warns if lockfile is not found (with -G)" do bundler_required expect(File).to receive(:exist?).with(/\.yardopts$/).at_least(:once).and_return(false) expect(File).to receive(:exist?).with('somefile.lock').and_return(false) expect(log).to receive(:warn).with(/Cannot find somefile.lock/) run '-G', 'somefile' end it "displays an error if Bundler not available (with -G)" do expect(@cli).to receive(:require).with('bundler').and_raise(LoadError) expect(log).to receive(:error).with(/Bundler not available/) run '-G' end it "loads template paths after adapter template paths" do unstub_adapter @cli.adapter = Server::WebrickAdapter run '-t', 'foo' expect(Templates::Engine.template_paths.last).to eq 'foo' end it "loads 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 expect(Templates::Engine.template_paths.last).to eq 'foo' end ensure File.unlink(path) end end end end yard-0.9.12/spec/cli/help_spec.rb0000755000004100000410000000114113206751010016555 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::CLI::Help do describe "#run" do it "accepts help command" do expect(CLI::Yardoc).to receive(:run).with('--help') CLI::Help.run('doc') end it "accepts no arguments (and lists all commands)" do expect(CLI::CommandParser).to receive(:run).with('--help') CLI::Help.run end it "shows all commands if command isn't found" do expect(CLI::CommandParser).to receive(:run).with('--help') help = CLI::Help.new expect(log).to receive(:puts).with(/not found/) help.run('unknown') end end end yard-0.9.12/spec/cli/gems_spec.rb0000755000004100000410000000641013206751010016564 0ustar www-datawww-data# frozen_string_literal: true require 'ostruct' require 'rubygems' RSpec.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| allow(Registry).to receive(:yardoc_file_for_gem).with(themock.name, "= #{themock.version}").and_return(themock.yardoc_file) allow(File).to receive(:directory?).with(themock.yardoc_file).and_return(@rebuild) allow(File).to receive(:directory?).with(themock.full_gem_path).and_return(true) allow(Registry).to receive(:yardoc_file_for_gem).with(themock.name, "= #{themock.version}", true).and_return(themock.yardoc_file) expect(Dir).to receive(:chdir).with(themock.full_gem_path).and_yield end expect(Registry).to receive(:clear).exactly(specs.size).times expect(CLI::Yardoc).to receive(:run).exactly(specs.size).times end describe "#run" do it "builds all gem indexes if no gem is specified" do build_specs(@gem1, @gem2) expect(YARD::GemIndex).to receive(:each) {|&b| [@gem1, @gem2].each(&b) } CLI::Gems.run end it "allows gem to be specified" do build_specs(@gem1) expect(YARD::GemIndex).to receive(:find_all_by_name).with(@gem1.name, '>= 0').and_return([@gem1]) CLI::Gems.run(@gem1.name) end it "allows multiple gems to be specified for building" do build_specs(@gem1, @gem2) expect(YARD::GemIndex).to receive(:find_all_by_name).with(@gem1.name, @gem1.version).and_return([@gem1]) expect(YARD::GemIndex).to receive(:find_all_by_name).with(@gem2.name, '>= 0').and_return([@gem2]) CLI::Gems.run(@gem1.name, @gem1.version, @gem2.name) end it "allows version to be specified with gem" do build_specs(@gem1) expect(YARD::GemIndex).to receive(:find_all_by_name).with(@gem1.name, '>= 1.0').and_return([@gem1]) CLI::Gems.run(@gem1.name, '>= 1.0') end it "warns if one of the gems is not found, but it should process others" do build_specs(@gem2) expect(YARD::GemIndex).to receive(:find_all_by_name).with(@gem1.name, '>= 2.0').and_return([]) expect(YARD::GemIndex).to receive(:find_all_by_name).with(@gem2.name, '>= 0').and_return([@gem2]) expect(log).to receive(:warn).with(/#{@gem1.name} >= 2.0 could not be found/) CLI::Gems.run(@gem1.name, '>= 2.0', @gem2.name) end it "fails if specified gem(s) is/are not found" do expect(CLI::Yardoc).not_to receive(:run) expect(YARD::GemIndex).to receive(:find_all_by_name).with(@gem1.name, '>= 2.0').and_return([]) expect(log).to receive(:warn).with(/#{@gem1.name} >= 2.0 could not be found/) expect(log).to receive(:error).with(/No specified gems could be found/) CLI::Gems.run(@gem1.name, '>= 2.0') end it "accepts --rebuild" do @rebuild = true build_specs(@gem1) expect(YARD::GemIndex).to receive(:each) {|&b| [@gem1].each(&b) } CLI::Gems.run('--rebuild') end end end yard-0.9.12/spec/cli/config_spec.rb0000755000004100000410000001060613206751010017100 0ustar www-datawww-data# frozen_string_literal: true require 'yaml' RSpec.describe YARD::CLI::Config do before do @config = YARD::CLI::Config.new YARD::Config.options = YARD::Config::DEFAULT_CONFIG_OPTIONS.dup allow(YARD::Config).to receive(:save) end def run(*args) @config.run(*args) end describe "Listing configuration" do it "accepts --list" do opts = YARD::Config.options expect(YAML).to receive(:dump).twice.and_return("--- foo\nbar\nbaz") expect(log).to receive(:puts).twice.with("bar\nbaz") run run('--list') expect(YARD::Config.options).to eq opts end end describe "Viewing an item" do it "views item if no value is given" do YARD::Config.options[:foo] = 'bar' expect(log).to receive(:puts).with('"bar"') run 'foo' expect(YARD::Config.options[:foo]).to eq 'bar' end end describe "Modifying an item" do it "accepts --reset to set value" do YARD::Config.options[:load_plugins] = 'foo' run('--reset', 'load_plugins') expect(YARD::Config.options[:load_plugins]).to be false end it "accepts --as-list to force single item as list" do run('--as-list', 'foo', 'bar') expect(YARD::Config.options[:foo]).to eq ['bar'] end it "accepts --append to append values to existing key" do YARD::Config.options[:foo] = ['bar'] run('--append', 'foo', 'baz', 'quux') expect(YARD::Config.options[:foo]).to eq ['bar', 'baz', 'quux'] run('-a', 'foo', 'last') expect(YARD::Config.options[:foo]).to eq ['bar', 'baz', 'quux', 'last'] end it "turns key into list if --append is used on single item" do YARD::Config.options[:foo] = 'bar' run('-a', 'foo', 'baz') expect(YARD::Config.options[:foo]).to eq ['bar', 'baz'] end it "modifies item if value is given" do run('foo', 'xxx') expect(YARD::Config.options[:foo]).to eq 'xxx' end it "turns list of values into array of values" do run('foo', 'a', 'b', '1', 'true', 'false') expect(YARD::Config.options[:foo]).to eq ['a', 'b', 1, true, false] end it "turns number into numeric Ruby type" do run('foo', '1') expect(YARD::Config.options[:foo]).to eq 1 end it "turns true into TrueClass" do run('foo', 'true') expect(YARD::Config.options[:foo]).to be true end it "turns false into FalseClass" do run('foo', 'false') expect(YARD::Config.options[:foo]).to be false end it "saves on modification" do expect(YARD::Config).to receive(:save) run('foo', 'true') end end describe "RubyGems hooks" do require 'rubygems' class FakeGemConfig < Hash attr_accessor :written def write; @written = true end def path; nil end end before do allow(Gem).to receive(:configuration).and_return(FakeGemConfig.new) end it "accepts --gem-install-yri" do @config.send(:optparse, '--gem-install-yri') expect(@config.gem_install_cmd).to eq 'yri' end it "accepts --gem-install-yard" do @config.send(:optparse, '--gem-install-yard') expect(@config.gem_install_cmd).to eq 'yard' end it "does not change back to yri if yard was specified" do @config.send(:optparse, '--gem-install-yard', '--gem-install-yri') expect(@config.gem_install_cmd).to eq 'yard' end it "ignores actual config options" do run('--gem-install-yri', 'foo', 'true') expect(YARD::Config).not_to receive(:save) end it "updates configuration as :gem if no configuration exists" do run('--gem-install-yri') expect(Gem.configuration[:gem]).to eq "--document=yri" expect(Gem.configuration.written).to eq true end [:install, "install", :gem, "gem"].each do |type| it "finds existing config in #{type.inspect} and updates that line without changing anything else" do Gem.configuration[type] = "--opts x" run('--gem-install-yri') expect(Gem.configuration[type]).to eq "--opts x --document=yri" ([:install, "install", :gem, "gem"] - [type]).each do |other| expect(Gem.configuration[other]).to eq nil end end end it "scrubs --document values from existing config" do Gem.configuration["gem"] = "--document=yri,ri --no-document --opts x" run('--gem-install-yri') expect(Gem.configuration["gem"]).to eq "--opts x --document=yri" end end end yard-0.9.12/spec/cli/yri_spec.rb0000755000004100000410000000726413206751010016444 0ustar www-datawww-data# frozen_string_literal: true class TestYRI < YARD::CLI::YRI public :optparse, :find_object, :cache_object def test_stub; end def print_object(*args) test_stub; super end end RSpec.describe YARD::CLI::YRI do before do @yri = TestYRI.new allow(Registry).to receive(:load) end describe "#find_object" do it "uses cache if available" do allow(@yri).to receive(:cache_object) expect(File).to receive(:exist?).with('.yardoc').and_return(false) expect(File).to receive(:exist?).with('bar.yardoc').and_return(true) expect(Registry).to receive(:load).with('bar.yardoc') expect(Registry).to receive(:at).ordered.with('Foo').and_return(nil) expect(Registry).to receive(:at).ordered.with('Foo').and_return('OBJ') @yri.instance_variable_set("@cache", 'Foo' => 'bar.yardoc') expect(@yri.find_object('Foo')).to eq 'OBJ' end it "never uses cache ahead of current directory's .yardoc" do allow(@yri).to receive(:cache_object) expect(File).to receive(:exist?).with('.yardoc').and_return(true) expect(Registry).to receive(:load).with('.yardoc') expect(Registry).to receive(:at).ordered.with('Foo').and_return(nil) expect(Registry).to receive(:at).ordered.with('Foo').and_return('OBJ') @yri.instance_variable_set("@cache", 'Foo' => 'bar.yardoc') expect(@yri.find_object('Foo')).to eq 'OBJ' expect(@yri.instance_variable_get("@search_paths")[0]).to eq '.yardoc' end end describe "#cache_object" do it "skips caching for Registry.yardoc_file" do expect(File).not_to receive(:open).with(CLI::YRI::CACHE_FILE, 'w') @yri.cache_object('Foo', Registry.yardoc_file) end end describe "#initialize" do it "loads search paths" do path = %r{/\.yard/yri_search_paths$} expect(File).to receive(:file?).with(%r{/\.yard/yri_cache$}).and_return(false) expect(File).to receive(:file?).with(path).and_return(true) expect(File).to receive(:readlines).with(path).and_return(%w(line1 line2)) @yri = YARD::CLI::YRI.new spaths = @yri.instance_variable_get("@search_paths") expect(spaths).to include('line1') expect(spaths).to include('line2') end it "uses DEFAULT_SEARCH_PATHS prior to other paths" do YARD::CLI::YRI::DEFAULT_SEARCH_PATHS.push('foo', 'bar') path = %r{/\.yard/yri_search_paths$} expect(File).to receive(:file?).with(%r{/\.yard/yri_cache$}).and_return(false) expect(File).to receive(:file?).with(path).and_return(true) expect(File).to receive(:readlines).with(path).and_return(%w(line1 line2)) @yri = YARD::CLI::YRI.new spaths = @yri.instance_variable_get("@search_paths") expect(spaths[0, 4]).to eq %w(foo bar line1 line2) YARD::CLI::YRI::DEFAULT_SEARCH_PATHS.replace([]) end end describe "#run" do it "searches for objects and print their documentation" do obj = YARD::CodeObjects::ClassObject.new(:root, 'Foo') expect(@yri).to receive(:print_object).with(obj) @yri.run('Foo') Registry.clear end it "prints usage if no object is provided" do expect(@yri).to receive(:print_usage) expect(@yri).to receive(:exit).with(1) @yri.run('') end it "prints 'no documentation exists for object' if object is not found" do expect(STDERR).to receive(:puts).with("No documentation for `Foo'") expect(@yri).to receive(:exit).with(1) @yri.run('Foo') end it "ensures output is serialized" do YARD::CodeObjects::ClassObject.new(:root, 'Foo') allow(@yri).to receive(:test_stub) do expect(@yri.instance_variable_get(:@serializer)).to receive(:serialize).once end @yri.run('Foo') end end end yard-0.9.12/spec/cli/stats_spec.rb0000755000004100000410000000535213206751010016773 0ustar www-datawww-data# frozen_string_literal: true require 'stringio' RSpec.describe YARD::CLI::Stats do before do Registry.clear YARD.parse_string <<-eof class A CONST = 1 def foo; end attr_reader :fooattr # 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" \ "Attributes: 1 ( 0 undocumented)\n" \ "Methods: 2 ( 1 undocumented)\n" \ " 33.33% documented\n" @output = StringIO.new @stats = CLI::Stats.new(false) allow(@stats).to receive(:support_rdoc_document_file!).and_return([]) allow(@stats).to receive(:yardopts).and_return([]) allow(log).to receive(:puts) {|*args| @output << args.join("\n") << "\n" } end it "lists undocumented objects with --list-undoc when there are undocumented objects" do @stats.run('--list-undoc') expect(@output.string).to eq <<-eof #{@main_stats} Undocumented Objects: (in file: (stdin)) A A#foo A::CONST B eof end it "lists no undocumented objects with --list-undoc when there is nothing undocumented" do Registry.clear YARD.parse_string <<-eof # documentation def foo; end eof @stats.run('--list-undoc') expect(@output.string).to eq "Files: 1\n" \ "Modules: 0 ( 0 undocumented)\n" \ "Classes: 0 ( 0 undocumented)\n" \ "Constants: 0 ( 0 undocumented)\n" \ "Attributes: 0 ( 0 undocumented)\n" \ "Methods: 1 ( 0 undocumented)\n" \ " 100.00% documented\n" end it "lists undocumented objects in compact mode with --list-undoc --compact" do @stats.run('--list-undoc', '--compact') expect(@output.string).to eq <<-eof #{@main_stats} Undocumented Objects: A ((stdin):1) A#foo ((stdin):4) A::CONST ((stdin):2) B ((stdin):11) eof end it "still lists stats with --quiet" do @stats.run('--quiet') expect(@output.string).to eq @main_stats end it "ignores everything with --no-public" do @stats.run('--no-public') expect(@output.string).to eq( "Files: 0\n" \ "Modules: 0 ( 0 undocumented)\n" \ "Classes: 0 ( 0 undocumented)\n" \ "Constants: 0 ( 0 undocumented)\n" \ "Attributes: 0 ( 0 undocumented)\n" \ "Methods: 0 ( 0 undocumented)\n" \ " 100.00% documented\n" ) end end yard-0.9.12/spec/cli/diff_spec.rb0000755000004100000410000001722013206751010016542 0ustar www-datawww-data# frozen_string_literal: true require 'stringio' require 'open-uri' RSpec.describe YARD::CLI::Diff do before do allow(CLI::Yardoc).to receive(:run) allow(CLI::Gems).to receive(:run) @diff = CLI::Diff.new end describe "Argument handling" do it "exits if there is only one gem name" do expect(@diff).to receive(:exit) expect(log).to 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] expect(@diff).to 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 expect(@diff).to 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 allow(log).to receive(:print) {|data| @data << data } allow(log).to receive(:puts) {|*pargs| @data << pargs.join("\n"); @data << "\n" } @diff.run(*(args + ['gem1', 'gem2'])) end it "shows differences between objects" do run expect(@data.string).to eq <<-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 "accepts --compact" do run('--compact') expect(@data.string).to eq <<-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 "accepts -a/--all" do ['-a', '--all'].each do |opt| run(opt) expect(@data.string).to eq <<-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 "accepts --compact and --all" do run('--compact', '--all') expect(@data.string).to eq <<-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 "accepts --no-modified" do run('--compact', '--no-modified') expect(@data.string).to eq <<-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 "accepts --query" do run('--compact', '--query', 'o.type == :method') expect(@data.string).to eq <<-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 allow(@diff).to receive(:generate_yardoc) end it "searches for gem/.yardoc" do expect(File).to receive(:directory?).with('gem1/.yardoc').and_return(true) expect(File).to receive(:directory?).with('gem2/.yardoc').and_return(true) expect(Registry).to receive(:load_yardoc).with('gem1/.yardoc') expect(Registry).to receive(:load_yardoc).with('gem2/.yardoc') @diff.run('gem1', 'gem2') end it "searches for argument as yardoc" do expect(File).to receive(:directory?).with('gem1/.yardoc').and_return(false) expect(File).to receive(:directory?).with('gem2/.yardoc').and_return(false) expect(File).to receive(:directory?).with('gem1').and_return(true) expect(File).to receive(:directory?).with('gem2').and_return(true) expect(Registry).to receive(:load_yardoc).with('gem1') expect(Registry).to receive(:load_yardoc).with('gem2') @diff.run('gem1', 'gem2') end it "searches for installed gem" do expect(File).to receive(:directory?).with('gem1-1.0.0.gem/.yardoc').and_return(false) expect(File).to receive(:directory?).with('gem2-1.0.0/.yardoc').and_return(false) expect(File).to receive(:directory?).with('gem1-1.0.0.gem').and_return(false) expect(File).to receive(:directory?).with('gem2-1.0.0').and_return(false) spec1 = double(:spec) spec2 = double(:spec) allow(YARD::GemIndex).to receive(:each) {|&b| [spec1, spec2].each(&b) } allow(spec1).to receive(:full_name).and_return('gem1-1.0.0') allow(spec1).to receive(:name).and_return('gem1') allow(spec1).to receive(:version).and_return('1.0.0') allow(spec2).to receive(:full_name).and_return('gem2-1.0.0') allow(spec2).to receive(:name).and_return('gem2') allow(spec2).to receive(:version).and_return('1.0.0') expect(Registry).to receive(:yardoc_file_for_gem).with('gem1', '= 1.0.0').and_return('/path/to/file') expect(Registry).to receive(:yardoc_file_for_gem).with('gem2', '= 1.0.0').and_return(nil) expect(Registry).to receive(:load_yardoc).with('/path/to/file') expect(CLI::Gems).to receive(:run).with('gem2', '1.0.0').and_return(nil) allow(Dir).to receive(:chdir) @diff.run('gem1-1.0.0.gem', 'gem2-1.0.0') end it "searches for .gem file" do expect(File).to receive(:directory?).with('gem1/.yardoc').and_return(false) expect(File).to receive(:directory?).with('gem2.gem/.yardoc').and_return(false) expect(File).to receive(:directory?).with('gem1').and_return(false) expect(File).to receive(:directory?).with('gem2.gem').and_return(false) expect(File).to receive(:exist?).with('gem1.gem').and_return(true) expect(File).to receive(:exist?).with('gem2.gem').and_return(true) expect(File).to receive(:open).with('gem1.gem', 'rb') expect(File).to receive(:open).with('gem2.gem', 'rb') allow(FileUtils).to receive(:mkdir_p) allow(Gem::Package).to receive(:open) allow(FileUtils).to receive(:rm_rf) @diff.run('gem1', 'gem2.gem') end it "searches for .gem file on rubygems.org" do expect(File).to receive(:directory?).with('gem1/.yardoc').and_return(false) expect(File).to receive(:directory?).with('gem2.gem/.yardoc').and_return(false) expect(File).to receive(:directory?).with('gem1').and_return(false) expect(File).to receive(:directory?).with('gem2.gem').and_return(false) expect(File).to receive(:exist?).with('gem1.gem').and_return(false) expect(File).to receive(:exist?).with('gem2.gem').and_return(false) expect(@diff).to receive(:open).with('http://rubygems.org/downloads/gem1.gem') expect(@diff).to receive(:open).with('http://rubygems.org/downloads/gem2.gem') allow(FileUtils).to receive(:mkdir_p) allow(Gem::Package).to receive(:open) allow(FileUtils).to receive(:rm_rf) @diff.run('gem1', 'gem2.gem') end it "raises an error if gem is not found" do expect(log).to receive(:error).with("Cannot find gem gem1") expect(log).to receive(:error).with("Cannot find gem gem2.gem") allow(@diff).to receive(:load_gem_data).and_return(false) @diff.run('gem1', 'gem2.gem') end end end yard-0.9.12/spec/cli/i18n_spec.rb0000755000004100000410000000644513206751010016420 0ustar www-datawww-data# frozen_string_literal: true RSpec.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) allow(File).to receive(:open!).with(output_path, "wb") allow(YARD).to receive(:parse) end describe "Defaults" do before do @i18n = YARD::CLI::I18n.new allow(@i18n).to receive(:yardopts).and_return([]) allow(@i18n).to receive(:support_rdoc_document_file!).and_return([]) @i18n.parse_arguments end it "reads .yardopts by default" do expect(@i18n.use_yardopts_file).to be true end it "only shows public visibility by default" do expect(@i18n.visibilities).to eq [: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("accepts #{arg}") { send("test_options_#{counter}", arg) } end end should_accept('--yardopts') do |arg| @i18n = YARD::CLI::I18n.new @i18n.use_document_file = false expect(@i18n).to receive(:yardopts).at_least(1).times.and_return([]) @i18n.parse_arguments(arg) expect(@i18n.use_yardopts_file).to be true @i18n.parse_arguments('--no-yardopts', arg) expect(@i18n.use_yardopts_file).to be true end should_accept('--yardopts with filename') do |_arg| @i18n = YARD::CLI::I18n.new expect(File).to receive(:read_binary).with('.yardopts_i18n').and_return('') @i18n.use_document_file = false @i18n.parse_arguments('--yardopts', '.yardopts_i18n') expect(@i18n.use_yardopts_file).to be true expect(@i18n.options_file).to eq '.yardopts_i18n' end should_accept('--no-yardopts') do |arg| @i18n = YARD::CLI::I18n.new @i18n.use_document_file = false expect(@i18n).not_to receive(:yardopts) @i18n.parse_arguments(arg) expect(@i18n.use_yardopts_file).to be false @i18n.parse_arguments('--yardopts', arg) expect(@i18n.use_yardopts_file).to be false end should_accept('--exclude') do |arg| expect(YARD).to 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 "searches for and uses yardopts file specified by #options_file" do expect(File).to receive(:read_binary).with("test").and_return("-o \n\nMYPATH\nFILE1 FILE2") @i18n.use_document_file = false @i18n.options_file = "test" expect(File).to receive(:open!).with(File.expand_path("MYPATH"), "wb") @i18n.run expect(@i18n.files).to eq ["FILE1", "FILE2"] end end describe "#run" do it "calls parse_arguments if run() is called" do expect(@i18n).to receive(:parse_arguments) @i18n.run end it "calls parse_arguments if run(arg1, arg2, ...) is called" do expect(@i18n).to receive(:parse_arguments) @i18n.run('--private', '-p', 'foo') end it "doesn't call parse_arguments if run(nil) is called" do expect(@i18n).not_to receive(:parse_arguments) @i18n.run(nil) end end end yard-0.9.12/spec/cli/graph_spec.rb0000755000004100000410000000112713206751010016732 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::CLI::Graph do it "serializes output" do allow(Registry).to receive(:load).at_least(1).times allow(subject).to receive(:yardopts) { [] } expect(subject.options.serializer).to receive(:serialize).once subject.run end it "reads yardoc file from .yardopts" do allow(Registry).to receive(:load).at_least(1).times allow(subject).to receive(:yardopts) { %w(--db /path/to/db) } expect(subject.options.serializer).to receive(:serialize).once subject.run expect(Registry.yardoc_file).to eq '/path/to/db' end end yard-0.9.12/spec/cli/markup_types_spec.rb0000755000004100000410000000121113206751010020346 0ustar www-datawww-data# frozen_string_literal: true RSpec.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| expect(data).to match(/\b#{name}\b/) # Match all extensions exts[name].each do |ext| expect(data).to include(".#{ext}") end if exts[name] # Match all provider libs providers.each do |provider| expect(data).to match(/\b#{provider[:lib]}\b/) end end end end yard-0.9.12/spec/cli/yardoc_spec.rb0000755000004100000410000007366213206751010017127 0ustar www-datawww-data# frozen_string_literal: true RSpec.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 allow(Templates::Engine).to receive(:render) allow(Templates::Engine).to receive(:generate) allow(YARD).to receive(:parse) allow(Registry).to receive(:load) allow(Registry).to receive(:save) allow(File).to receive(:open!) end describe "Defaults" do before do @yardoc = CLI::Yardoc.new allow(@yardoc).to receive(:yardopts).and_return([]) allow(@yardoc).to receive(:support_rdoc_document_file!).and_return([]) @yardoc.parse_arguments end it "does not use cache by default" do expect(@yardoc.use_cache).to be false end it "prints statistics by default" do expect(@yardoc.statistics).to be true end it "generates output by default" do expect(@yardoc.generate).to be true end it "reads .yardopts by default" do expect(@yardoc.use_yardopts_file).to be true end it "reads .document by default" do expect(@yardoc.use_document_file).to be true end it "uses lib, app, and ext as default file glob paths" do expect(@yardoc.files).to eq Parser::SourceParser::DEFAULT_PATH_GLOB end it "uses rdoc as default markup type (but falls back on none)" do expect(@yardoc.options.markup).to eq :rdoc end it "uses default as default template" do expect(@yardoc.options.template).to eq :default end it "uses HTML as default format" do expect(@yardoc.options.format).to eq :html end it "uses 'Object' as default return type" do expect(@yardoc.options.default_return).to eq 'Object' end it "does not hide void return types by default" do expect(@yardoc.options.hide_void_return).to be false end it "only shows public visibility by default" do expect(@yardoc.visibilities).to eq [:public] end it "does not list objects by default" do expect(@yardoc.list).to be false end it "does not embed mixins by default" do expect(@yardoc.options.embed_mixins).to be_empty end it "does not set any locale by default" do expect(@yardoc.options.locale).to be nil end end describe "General options" do def self.should_accept(*args, &block) @counter ||= 0 @counter += 1 counter = @counter define_method("test_options_#{@counter}", &block) args.each do |arg| it("accepts #{arg}") { send("test_options_#{counter}", arg) } end end should_accept('--single-db') do |arg| @yardoc.parse_arguments(arg) expect(Registry.single_object_db).to be true Registry.single_object_db = nil end should_accept('--no-single-db') do |arg| @yardoc.parse_arguments(arg) expect(Registry.single_object_db).to be false Registry.single_object_db = nil end should_accept('-c', '--use-cache') do |arg| @yardoc.parse_arguments(arg) expect(@yardoc.use_cache).to be true end should_accept('--no-cache') do |arg| @yardoc.parse_arguments(arg) expect(@yardoc.use_cache).to be false end should_accept('--yardopts') do |arg| @yardoc = CLI::Yardoc.new @yardoc.use_document_file = false expect(@yardoc).to receive(:yardopts).at_least(1).times.and_return([]) @yardoc.parse_arguments(arg) expect(@yardoc.use_yardopts_file).to be true @yardoc.parse_arguments('--no-yardopts', arg) expect(@yardoc.use_yardopts_file).to be true end should_accept('--yardopts with filename') do |_arg| @yardoc = CLI::Yardoc.new expect(File).to receive(:read_binary).with('.foobar').and_return('') @yardoc.use_document_file = false @yardoc.parse_arguments('--yardopts', '.foobar') expect(@yardoc.use_yardopts_file).to be true expect(@yardoc.options_file).to eq '.foobar' end should_accept('--no-yardopts') do |arg| @yardoc = CLI::Yardoc.new @yardoc.use_document_file = false expect(@yardoc).not_to receive(:yardopts) @yardoc.parse_arguments(arg) expect(@yardoc.use_yardopts_file).to be false @yardoc.parse_arguments('--yardopts', arg) expect(@yardoc.use_yardopts_file).to be false end should_accept('--document') do |arg| @yardoc = CLI::Yardoc.new @yardoc.use_yardopts_file = false expect(@yardoc).to receive(:support_rdoc_document_file!).and_return([]) @yardoc.parse_arguments('--no-document', arg) expect(@yardoc.use_document_file).to be true end should_accept('--no-document') do |arg| @yardoc = CLI::Yardoc.new @yardoc.use_yardopts_file = false expect(@yardoc).not_to receive(:support_rdoc_document_file!) @yardoc.parse_arguments('--document', arg) expect(@yardoc.use_document_file).to be false end should_accept('-b', '--db') do |arg| @yardoc.parse_arguments(arg, 'test') expect(Registry.yardoc_file).to eq 'test' Registry.yardoc_file = '.yardoc' end should_accept('-n', '--no-output') do |arg| expect(Templates::Engine).not_to receive(:generate) @yardoc.run(arg) end should_accept('--exclude') do |arg| expect(YARD).to receive(:parse).with(['a'], ['nota', 'b']) @yardoc.run(arg, 'nota', arg, 'b', 'a') end should_accept('--no-save') do |arg| expect(YARD).to receive(:parse) expect(Registry).not_to receive(:save) @yardoc.run(arg) end should_accept('--fail-on-warning') do |arg| expect(YARD).to receive(:parse) @yardoc.run(arg) end end describe "Output options" do it "accepts --title" do @yardoc.parse_arguments('--title', 'hello world') expect(@yardoc.options.title).to eq 'hello world' end it "allows --title to have multiple spaces in .yardopts" do expect(File).to receive(:read_binary).with("test").and_return("--title \"Foo Bar\"") @yardoc.options_file = "test" @yardoc.use_yardopts_file = true @yardoc.run expect(@yardoc.options.title).to eq "Foo Bar" end it "aliases --main to the --readme flag" do Dir.chdir(File.join(File.dirname(__FILE__), '..', '..')) do @yardoc.parse_arguments('--main', 'README.md') expect(@yardoc.options.readme).to eq CodeObjects::ExtraFileObject.new('README.md', '') end end it "selects a markup provider when --markup-provider or -mp is set" do @yardoc.parse_arguments("-M", "test") expect(@yardoc.options.markup_provider).to eq :test @yardoc.parse_arguments("--markup-provider", "test2") expect(@yardoc.options.markup_provider).to eq :test2 end it "selects a markup format when -m is set" do expect(@yardoc).to receive(:verify_markup_options).and_return(true) @yardoc.generate = true @yardoc.parse_arguments('-m', 'markdown') expect(@yardoc.options.markup).to eq :markdown end it "accepts --default-return" do @yardoc.parse_arguments(*%w(--default-return XYZ)) expect(@yardoc.options.default_return).to eq "XYZ" end it "allows --hide-void-return to be set" do @yardoc.parse_arguments(*%w(--hide-void-return)) expect(@yardoc.options.hide_void_return).to be true end it "accepts --embed-mixins" do @yardoc.parse_arguments(*%w(--embed-mixins)) expect(@yardoc.options.embed_mixins).to eq ['*'] end it "accepts --embed-mixin MODULE" do @yardoc.parse_arguments(*%w(--embed-mixin MyModule)) expect(@yardoc.options.embed_mixins).to eq ['MyModule'] end it "generates all objects with --use-cache" do expect(YARD).to receive(:parse) expect(Registry).to receive(:load) expect(Registry).to receive(:load_all) allow(@yardoc).to receive(:generate).and_return(true) @yardoc.run(*%w(--use-cache)) end it "does not print statistics with --no-stats" do allow(@yardoc).to receive(:statistics).and_return(false) expect(CLI::Stats).not_to receive(:new) @yardoc.run(*%w(--no-stats)) end it "disables progress bar with --no-progress" do old = log.show_progress log.show_progress = true @yardoc.run(*%w(--no-progress)) expect(log.show_progress).to eq false log.show_progress = old end describe "--asset" do before do @yardoc.generate = true allow(@yardoc).to receive(:run_generate) end it "copies assets to output directory" do expect(FileUtils).to receive(:cp_r).with('a', 'doc/a') @yardoc.run(*%w(--asset a)) expect(@yardoc.assets).to eq('a' => 'a') end it "allows multiple --asset options" do expect(FileUtils).to receive(:cp_r).with('a', 'doc/a') expect(FileUtils).to receive(:cp_r).with('b', 'doc/b') @yardoc.run(*%w(--asset a --asset b)) expect(@yardoc.assets).to eq('a' => 'a', 'b' => 'b') end it "does not allow from or to to refer to a path above current path" do expect(log).to receive(:warn).exactly(4).times.with(/invalid/i) @yardoc.run(*%w(--asset ../../../etc/passwd)) expect(@yardoc.assets).to be_empty @yardoc.run(*%w(--asset a/b/c/d/../../../../../../etc/passwd)) expect(@yardoc.assets).to be_empty @yardoc.run(*%w(--asset /etc/passwd)) expect(@yardoc.assets).to be_empty @yardoc.run(*%w(--asset normal:/etc/passwd)) expect(@yardoc.assets).to be_empty end it "allows from:to syntax" do expect(FileUtils).to receive(:cp_r).with(%r{foo(\/\.)?}, 'doc/bar') @yardoc.run(*%w(--asset foo:bar)) expect(@yardoc.assets).to eq('foo' => 'bar') end it "does 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}") expect(File.directory?(full_to)).to be true expect(File.directory?(File.join(full_to, 'tmp_foo'))).to be false ensure FileUtils.rm_rf(from) FileUtils.rm_rf(full_to) end end end describe "--locale" do it "applies specified locale to all extra file objects" do allow(File).to receive(:read).with('extra_file1').and_return('') allow(File).to receive(:read).with('extra_file2').and_return('') extra_file_object1 = CodeObjects::ExtraFileObject.new('extra_file1') extra_file_object2 = CodeObjects::ExtraFileObject.new('extra_file2') expect(extra_file_object1).to receive(:locale=).with('fr') expect(extra_file_object2).to receive(:locale=).with('fr') allow(CodeObjects::ExtraFileObject).to receive(:new).with('extra_file1').and_return(extra_file_object1) allow(CodeObjects::ExtraFileObject).to receive(:new).with('extra_file2').and_return(extra_file_object2) allow(Dir).to receive(:glob).with('README{,*[^~]}').and_return([]) allow(File).to receive(:file?).with('extra_file1').and_return(true) allow(File).to receive(:file?).with('extra_file2').and_return(true) @yardoc.run('--locale=fr', '-', 'extra_file1', 'extra_file2') end end describe "--po-dir" do it "sets Registry.po_dir" do expect(Registry).to receive(:po_dir=).with("locale") @yardoc.run('--po-dir=locale') end end end describe "--[no-]api" do before { Registry.clear } it "allows --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') expect(@yardoc.options.verifier.run(Registry.all)).to eq [P('Foo')] end it "allows 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') expect(@yardoc.options.verifier.run(Registry.all). sort_by(&:path)).to eq [P('Bar'), P('Foo')] end it "allows --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', '') expect(@yardoc.options.verifier.run(Registry.all)).to eq [P('Baz')] @yardoc.options.verifier = Verifier.new @yardoc.run('--no-api') expect(@yardoc.options.verifier.run(Registry.all)).to eq [P('Baz')] end it "allows --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') expect(@yardoc.options.verifier.run(Registry.all). sort_by(&:path)).to eq [P('Bar'), P('Baz')] end it "ensures Ruby code cannot be used" do [':symbol', '42', '"; exit'].each do |ruby| @yardoc.options.verifier.expressions = [] @yardoc.run('--api', ruby) expect(@yardoc.options.verifier.expressions[1]).to include(ruby.inspect) end end end describe "--hide-api option" do it "allows --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') expect(@yardoc.options.verifier.run(Registry.all). sort_by(&:path)).to eq [P('Bar'), P('Baz')] end it "allows --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') expect(@yardoc.options.verifier.run(Registry.all). sort_by(&:path)).to eq [P('Bar')] end end describe "--no-private option" do it "accepts --no-private" do obj = double(:object) expect(obj).to receive(:tag).ordered.with(:private).and_return(true) @yardoc.parse_arguments(*%w(--no-private)) expect(@yardoc.options.verifier.call(obj)).to be false end it "hides object if namespace is @private with --no-private" do ns = double(:namespace, :type => :module) expect(ns).to receive(:tag).with(:private).and_return(true) obj = double(:object, :namespace => ns) expect(obj).to receive(:tag).with(:private).and_return(false) @yardoc.parse_arguments(*%w(--no-private)) expect(@yardoc.options.verifier.call(obj)).to be false end it "does not call #tag on namespace if namespace is proxy with --no-private" do ns = double(:namespace) expect(ns).to receive(:is_a?).with(CodeObjects::Proxy).and_return(true) expect(ns).not_to receive(:tag) obj = double(:object, :type => :class, :namespace => ns, :visibility => :public) expect(obj).to receive(:tag).ordered.with(:private).and_return(false) @yardoc.parse_arguments(*%w(--no-private)) expect(@yardoc.options.verifier.call(obj)).to be true end # @bug gh-197 it "does 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)) expect(@yardoc.options.verifier.call(foobar)).to be true end it "does not call #tag on proxy object" do # @bug gh-197 @yardoc.parse_arguments(*%w(--no-private)) expect(@yardoc.options.verifier.call(P('ProxyClass'))).to be true end it "hides 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)) expect(@yardoc.options.verifier.call(Registry.at('ABC'))).to be false expect(@yardoc.options.verifier.call(Registry.at('ABC#foo'))).to be false end end describe ".yardopts and .document handling" do before do @yardoc.use_yardopts_file = true end it "searches for and uses yardopts file specified by #options_file" do expect(File).to receive(:read_binary).with("test").and_return("-o \n\nMYPATH\nFILE1 FILE2") @yardoc.use_document_file = false @yardoc.options_file = "test" @yardoc.run expect(@yardoc.options.serializer.options[:basepath]).to eq "MYPATH" expect(@yardoc.files).to eq ["FILE1", "FILE2"] end it "uses String#shell_split to split .yardopts tokens" do optsdata = String.new("foo bar") expect(optsdata).to receive(:shell_split) expect(File).to receive(:read_binary).with("test").and_return(optsdata) @yardoc.options_file = "test" @yardoc.run end it "allows opts specified in command line to override yardopts file" do expect(File).to receive(:read_binary).with(".yardopts").and_return("-o NOTMYPATH") @yardoc.run("-o", "MYPATH", "FILE") expect(@yardoc.options.serializer.options[:basepath]).to eq "MYPATH" expect(@yardoc.files).to eq ["FILE"] end it "loads the RDoc .document file if found" do expect(File).to receive(:read_binary).with(".yardopts").and_return("-o NOTMYPATH") @yardoc.use_document_file = true allow(@yardoc).to receive(:support_rdoc_document_file!).and_return(["FILE2", "FILE3"]) @yardoc.run("-o", "MYPATH", "FILE1") expect(@yardoc.options.serializer.options[:basepath]).to eq "MYPATH" expect(@yardoc.files).to eq ["FILE2", "FILE3", "FILE1"] end end describe "Query options" do after { Registry.clear } it "hides private constants in with default visibilities" do classobj = CodeObjects::ClassObject.new(:root, :Foo) {|o| o.visibility = :private } @yardoc.run expect(@yardoc.options.verifier.run([classobj])).to eq [] end it "sets up visibility rules as verifier" do methobj = CodeObjects::MethodObject.new(:root, :test) {|o| o.visibility = :private } expect(File).to receive(:read_binary).with("test").and_return("--private") @yardoc.use_yardopts_file = true @yardoc.options_file = "test" @yardoc.run expect(@yardoc.options.verifier.call(methobj)).to be true end it "accepts a --query" do @yardoc.parse_arguments(*%w(--query @return)) expect(@yardoc.options.verifier).to be_a(Verifier) end it "accepts multiple --query arguments" do obj = double(:object) expect(obj).to receive(:tag).ordered.with('return').and_return(true) expect(obj).to receive(:tag).ordered.with('tag').and_return(false) @yardoc.parse_arguments(*%w(--query @return --query @tag)) expect(@yardoc.options.verifier).to be_a(Verifier) expect(@yardoc.options.verifier.call(obj)).to be false end end describe "Extra file arguments" do it "accepts extra files if specified after '-' with source files" do expect(Dir).to receive(:glob).with('README{,*[^~]}').and_return([]) expect(File).to receive(:file?).with('extra_file1').and_return(true) expect(File).to receive(:file?).with('extra_file2').and_return(true) expect(File).to receive(:read).with('extra_file1').and_return('') expect(File).to receive(:read).with('extra_file2').and_return('') @yardoc.parse_arguments(*%w(file1 file2 - extra_file1 extra_file2)) expect(@yardoc.files).to eq %w(file1 file2) expect(@yardoc.options.files).to eq( [CodeObjects::ExtraFileObject.new('extra_file1', ''), CodeObjects::ExtraFileObject.new('extra_file2', '')] ) end it "accepts files section only containing extra files" do expect(Dir).to receive(:glob).with('README{,*[^~]}').and_return([]) @yardoc.parse_arguments(*%w(- LICENSE)) expect(@yardoc.files).to eq Parser::SourceParser::DEFAULT_PATH_GLOB expect(@yardoc.options.files).to eq [CodeObjects::ExtraFileObject.new('LICENSE', '')] end it "accepts globs as extra files" do expect(Dir).to receive(:glob).with('README{,*[^~]}').and_return [] expect(Dir).to receive(:glob).with('*.txt').and_return ['a.txt', 'b.txt'] expect(File).to receive(:read).with('a.txt').and_return('') expect(File).to receive(:read).with('b.txt').and_return('') expect(File).to receive(:file?).with('a.txt').and_return(true) expect(File).to receive(:file?).with('b.txt').and_return(true) @yardoc.parse_arguments(*%w(file1 file2 - *.txt)) expect(@yardoc.files).to eq %w(file1 file2) expect(@yardoc.options.files).to eq( [CodeObjects::ExtraFileObject.new('a.txt', ''), CodeObjects::ExtraFileObject.new('b.txt', '')] ) end it "warns if extra file is not found" do expect(log).to receive(:warn).with(/Could not find file: UNKNOWN/) @yardoc.parse_arguments(*%w(- UNKNOWN)) end it "warns if readme file is not found" do expect(log).to receive(:warn).with(/Could not find file: UNKNOWN/) @yardoc.parse_arguments(*%w(-r UNKNOWN)) end it "warns on absolute paths in extra files" do expect(log).to receive(:warn).with(%r{Invalid file: /path/to/file}) @yardoc.parse_arguments(*%w(- /path/to/file)) end it "warns on absolute paths in readme" do expect(log).to receive(:warn).with(%r{Invalid file: /path/to/file}) @yardoc.parse_arguments(*%w(-r /path/to/file)) end it "uses first file as readme if no readme is specified when using --one-file" do expect(Dir).to receive(:glob).with('README{,*[^~]}').and_return [] expect(Dir).to receive(:glob).with('lib/*.rb').and_return(['lib/foo.rb']) expect(File).to receive(:read).with('lib/foo.rb').and_return('') @yardoc.parse_arguments(*%w(--one-file lib/*.rb)) expect(@yardoc.options.readme).to eq CodeObjects::ExtraFileObject.new('lib/foo.rb', '') end it "uses readme it exists when using --one-file" do expect(Dir).to receive(:glob).with('README{,*[^~]}').and_return ['README'] expect(File).to receive(:read).with('README').and_return('') @yardoc.parse_arguments(*%w(--one-file lib/*.rb)) expect(@yardoc.options.readme).to eq CodeObjects::ExtraFileObject.new('README', '') end it "does not allow US-ASCII charset when using --one-file" do ienc = Encoding.default_internal eenc = Encoding.default_external expect(log).to receive(:warn).with(/not compatible with US-ASCII.*using ASCII-8BIT/) @yardoc.parse_arguments(*%w(--one-file --charset us-ascii)) expect(Encoding.default_internal.name).to eq 'ASCII-8BIT' expect(Encoding.default_external.name).to eq 'ASCII-8BIT' Encoding.default_internal = ienc Encoding.default_external = eenc end if defined?(::Encoding) end describe "Source file arguments" do it "accepts no params and parse {lib,app}/**/*.rb ext/**/*.c" do @yardoc.parse_arguments expect(@yardoc.files).to eq Parser::SourceParser::DEFAULT_PATH_GLOB end end describe "Tags options" do def tag_created(switch, factory_method) visible_tags = double(:visible_tags) expect(visible_tags).to receive(:|).ordered.with([:foo]) expect(visible_tags).to receive(:-).ordered.with([]).and_return(visible_tags) expect(Tags::Library).to receive(:define_tag).with('Foo', :foo, factory_method) allow(Tags::Library).to receive(:visible_tags=) expect(Tags::Library).to receive(:visible_tags).at_least(1).times.and_return(visible_tags) @yardoc.parse_arguments("--#{switch}-tag", 'foo') end def tag_hidden(tag) visible_tags = double(:visible_tags) expect(visible_tags).to receive(:|).ordered.with([tag]) expect(visible_tags).to receive(:-).ordered.with([tag]).and_return([]) expect(Tags::Library).to receive(:define_tag).with(tag.to_s.capitalize, tag, nil) allow(Tags::Library).to receive(:visible_tags=) expect(Tags::Library).to receive(:visible_tags).at_least(1).times.and_return(visible_tags) end it "accepts --tag" do expect(Tags::Library).to receive(:define_tag).with('Title of Foo', :foo, nil) @yardoc.parse_arguments('--tag', 'foo:Title of Foo') end it "accepts --tag without title (and default to capitalized tag name)" do expect(Tags::Library).to receive(:define_tag).with('Foo', :foo, nil) @yardoc.parse_arguments('--tag', 'foo') end it "only lists tag once if declared twice" do visible_tags = [] allow(Tags::Library).to receive(:define_tag) allow(Tags::Library).to receive(:visible_tags).and_return([:foo]) allow(Tags::Library).to receive(:visible_tags=) {|value| visible_tags = value } @yardoc.parse_arguments('--tag', 'foo', '--tag', 'foo') expect(visible_tags).to eq [:foo] end it "accepts --type-tag" do tag_created 'type', :with_types end it "accepts --type-name-tag" do tag_created 'type-name', :with_types_and_name end it "accepts --name-tag" do tag_created 'name', :with_name end it "accepts --title-tag" do tag_created 'title', :with_title_and_text end it "accepts --hide-tag before tag is listed" do tag_hidden(:anewfoo) @yardoc.parse_arguments('--hide-tag', 'anewfoo', '--tag', 'anewfoo') end it "accepts --hide-tag after tag is listed" do tag_hidden(:anewfoo2) @yardoc.parse_arguments('--tag', 'anewfoo2', '--hide-tag', 'anewfoo2') end it "accepts --transitive-tag" do @yardoc.parse_arguments('--transitive-tag', 'foo') expect(Tags::Library.transitive_tags).to include(:foo) end it "accepts --non-transitive-tag" do Tags::Library.transitive_tags |= [:foo] @yardoc.parse_arguments('--non-transitive-tag', 'foo') expect(Tags::Library.transitive_tags).not_to include(:foo) end end describe "Safe mode" do before do allow(YARD::Config).to receive(:options).and_return(:safe_mode => true) end it "does not allow --load or -e in safe mode" do expect(@yardoc).not_to receive(:require) @yardoc.run('--load', 'foo') @yardoc.run('-e', 'foo') end it "does not allow --query in safe mode" do @yardoc.run('--query', 'foo') expect(@yardoc.options.verifier.expressions).not_to include("foo") end it "does not allow modifying the template paths" do expect(YARD::Templates::Engine).not_to receive(:register_template_path) @yardoc.run('-p', 'foo') @yardoc.run('--template-path', 'foo') end end describe "Markup Loading" do it "loads rdoc markup if no markup is provided" do @yardoc.generate = true @yardoc.run expect(@yardoc.options.markup).to eq :rdoc end it "loads rdoc markup even when no output is specified" do @yardoc.parse_arguments('--no-output') expect(@yardoc.options.markup).to eq :rdoc end it "warns if rdoc cannot be loaded and fallback to :none" do mod = YARD::Templates::Helpers::MarkupHelper mod.clear_markup_cache expect(mod.const_get(:MARKUP_PROVIDERS)).to receive(:[]).with(:rdoc).and_return([{:lib => 'INVALID'}]) expect(log).to receive(:warn).with(/Could not load default RDoc formatter/) allow(@yardoc).to receive(:generate) { @yardoc.options.files = []; true } @yardoc.run expect(@yardoc.options.markup).to eq :none mod.clear_markup_cache end it "returns an error immediately if markup for any files are missing" do mod = YARD::Templates::Helpers::MarkupHelper mod.clear_markup_cache expect(mod.const_get(:MARKUP_PROVIDERS)).to receive(:[]).with(:markdown).and_return([{:lib => 'INVALID'}]) expect(log).to receive(:error).with(/Missing 'INVALID' gem for Markdown formatting/) files = [CodeObjects::ExtraFileObject.new('test.md', '')] allow(@yardoc).to receive(:generate) { @yardoc.options.files = files; true } @yardoc.run mod.clear_markup_cache end it "returns an error immediately if markup for any files are missing (file markup specified in attributes)" do mod = YARD::Templates::Helpers::MarkupHelper mod.clear_markup_cache expect(mod.const_get(:MARKUP_PROVIDERS)).to receive(:[]).with(:markdown).and_return([{:lib => 'INVALID'}]) expect(log).to receive(:error).with(/Missing 'INVALID' gem for Markdown formatting/) files = [CodeObjects::ExtraFileObject.new('test', '# @markup markdown')] allow(@yardoc).to receive(:generate) { @yardoc.options.files = files; true } @yardoc.run mod.clear_markup_cache end end describe "#run" do it "parses arguments if run() is called" do expect(@yardoc).to receive(:parse_arguments) @yardoc.run end it "parses arguments if run(arg1, arg2, ...) is called" do expect(@yardoc).to receive(:parse_arguments) @yardoc.run('--private', '-p', 'foo') end it "does not parse arguments if run(nil) is called" do expect(@yardoc).not_to receive(:parse_arguments) @yardoc.run(nil) end it "creates processing lock if saving" do expect(Registry).to receive(:lock_for_writing).and_yield @yardoc.run end it "does not create processing lock if not saving" do expect(Registry).not_to receive(:lock_for_writing) @yardoc.run('--no-save') end context "with --fail-on-warning" do it "exits with error status code if a warning occurs" do allow(log).to receive(:warned).and_return(true) expect { @yardoc.run("--fail-on-warning") }.to raise_error(SystemExit) do |error| expect(error).not_to be_success end end it "does not exit if a warning does not occur" do allow(log).to receive(:warned).and_return(false) expect { @yardoc.run("--fail-on-warning") }.not_to raise_error end end end end yard-0.9.12/spec/cli/display_spec.rb0000755000004100000410000000177613206751010017310 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::CLI::Display do before do allow(Registry).to receive(:load) @object = CodeObjects::ClassObject.new(:root, :Foo) @object.docstring = 'Foo bar' end it "displays an object" do YARD::CLI::Display.run('-f', 'text', 'Foo') expect(log.io.string.strip).to 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 expect(actual_output).not_to eq(formatted_output) expect(actual_output).to 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 expect(actual_output).not_to eq(formatted_output) expect(actual_output).to include(formatted_output) end end yard-0.9.12/spec/cli/list_spec.rb0000755000004100000410000000035413206751010016605 0ustar www-datawww-data# frozen_string_literal: true RSpec.describe YARD::CLI::List do it "passes command off to Yardoc with --list" do expect(YARD::CLI::Yardoc).to receive(:run).with('-c', '--list', '--foo') YARD::CLI::List.run('--foo') end end yard-0.9.12/spec/cli/command_spec.rb0000755000004100000410000000207513206751010017252 0ustar www-datawww-data# frozen_string_literal: true require 'optparse' RSpec.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 "skips unrecognized options but continue to next option" do expect(log).to receive(:warn).with(/Unrecognized.*--list/) expect(log).to receive(:warn).with(/Unrecognized.*--list2/) parse('--list', '--list2', '--foo') expect(@saw_foo).to be true end it "skips unrecognized options and any extra non-option arg that follows" do expect(log).to receive(:warn).with(/Unrecognized.*--list/) parse('--list', 'foo', '--foo') expect(@saw_foo).to be true end it "stops retrying to parse at non-switch argument" do expect(log).to receive(:warn).with(/Unrecognized.*--list/) args = parse('--list', 'foo', 'foo', 'foo') expect(args).to eq %w(foo foo) end end end yard-0.9.12/spec/docstring_parser_spec.rb0000755000004100000410000001611313206751010020433 0ustar www-datawww-data# frozen_string_literal: true RSpec.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 "parses 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) expect(tags[0].name).to eq "name" expect(tags[0].text).to eq "Hello world\nhow are you?" expect(tags[1].name).to eq "name2" expect(tags[1].text).to eq "this is a new line" expect(tags[2].name).to eq "name3" expect(tags[2].text).to eq "and this\nis a new paragraph:\n\nright here." end it "ends parsing a tag on de-dent" do doc = docstring(<<-eof) @note test one two three rest of docstring eof expect(doc.tag(:note).text).to eq "test\none two three" expect(doc).to eq "rest of docstring" end it "parses 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 expect(doc).to eq "test string here\nmore stuff" expect(doc.tag(:example).text).to eq "\ndef foo(x, y, z)\nend\n\nclass A; end" end it "removes only original indentation from beginning of line in tags" do doc = docstring(<<-eof) @param name some value foo bar baz eof expect(doc.tag(:param).text).to eq "some value\nfoo bar\n baz" end it "allows 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 expect(doc.tag(:foo1).text).to eq "bar1" expect(doc.tag(:foo2).text).to eq "bar2" end it "ends tag on newline if next line is not indented" do doc = docstring(<<-eof) @author bar1 @api bar2 Hello world eof expect(doc.tag(:author).text).to eq "bar1" expect(doc.tag(:api).text).to eq "bar2" end it "warns about unknown tag" do expect(log).to receive(:warn).with(/Unknown tag @hello$/) docstring("@hello world") end it "does not add trailing whitespace to freeform tags" do doc = docstring("@api private \t ") expect(doc.tag(:api).text).to eq "private" end end describe "#parse with custom tag library" do class TestLibrary < Tags::Library; end before { @library = TestLibrary.new } it "accepts 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') expect(doc.tag(tag).text).to eq 'foo bar' end end it "does not parse invalid tag names" do invalid = %w(@ @return@ @p,aram @x-y @.x.y.z) invalid.each do |tag| expect(docstring(tag + ' foo bar')).to eq tag + ' foo bar' end end it "allows namespaced tags in the form @x.y.z" do TestLibrary.define_tag("Tag", 'x.y.z') doc = docstring("@x.y.z foo bar") expect(doc.tag('x.y.z').text).to eq 'foo bar' end it "ignores new directives without @! prefix syntax" do TestLibrary.define_directive('dir1', Tags::ScopeDirective) expect(log).to receive(:warn).with(/@dir1/) docstring("@dir1") end %w(attribute endgroup group macro method scope visibility).each do |tag| it "handles non prefixed @#{tag} syntax as directive, not tag" do TestLibrary.define_directive(tag, Tags::ScopeDirective) parse("@#{tag}") expect(@parser.directives.first).to be_a(Tags::ScopeDirective) end end it "handles directives with @! prefix syntax" do TestLibrary.define_directive('dir2', Tags::ScopeDirective) docstring("@!dir2 class") expect(@parser.state.scope).to eq :class end end describe "#text" do it "only returns text data" do parse("Foo\n@param foo x y z\nBar") expect(@parser.text).to eq "Foo\nBar" end end describe "#raw_text" do it "returns the entire original data" do data = "Foo\n@param foo x y z\nBar" parse(data) expect(@parser.raw_text).to eq data end end describe "#tags" do it "returns the parsed tags" do data = "Foo\n@param foo x y z\nBar" parse(data) expect(@parser.tags.size).to eq 1 expect(@parser.tags.first.tag_name).to eq 'param' end end describe "#directives" do it "groups all processed directives" do data = "Foo\n@!scope class\n@!visibility private\nBar" parse(data) dirs = @parser.directives expect(dirs[0]).to be_a(Tags::ScopeDirective) expect(dirs[0].tag.text).to eq 'class' expect(dirs[1]).to be_a(Tags::VisibilityDirective) expect(dirs[1].tag.text).to eq 'private' end end describe "#state" do it "handles modified state" do parse("@!scope class") expect(@parser.state.scope).to eq :class end end describe "after_parse (param)" do it "allows specifying of callbacks" do parser = DocstringParser.new the_yielded_obj = nil DocstringParser.after_parse {|obj| the_yielded_obj = obj } parser.parse("Some text") expect(the_yielded_obj).to eq parser end it "warns about invalid named parameters" do expect(log).to receive(:warn).with(/@param tag has unknown parameter name: notaparam/) YARD.parse_string <<-eof # @param notaparam foo def foo(a) end eof end it "warns about invalid named parameters on @!method directives" do expect(log).to receive(:warn).with(/@param tag has unknown parameter name: notaparam/) YARD.parse_string <<-eof # @!method foo(a) # @param notaparam foo test eof end it "warns about duplicate named parameters" do expect(log).to 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 it "does not warn on aliases" do expect(log).to_not receive(:warn) YARD.parse_string <<-eof # @param a foo def foo(a) end alias bar foo eof end end describe "after_parse (see)" do it "does not warn on valid see tag" do expect(log).to_not receive(:warn) YARD.parse_string "# @see valid\nclass Foo;end" end it "warns if {} wraps single name" do expect(log).to receive(:warn).with(/@see tag \(#1\) should not be wrapped in \{\}/) YARD.parse_string "# @see {invalid}\nclass Foo;end" end it "warns if {} wraps across name and text" do expect(log).to receive(:warn).with(/@see tag \(#1\) should not be wrapped in \{\}/) YARD.parse_string "# @see {invalid tag}\nclass Foo;end" end end end yard-0.9.12/lib/0000755000004100000410000000000013206751010013333 5ustar www-datawww-datayard-0.9.12/lib/rubygems_plugin.rb0000755000004100000410000000060513206751010017077 0ustar www-datawww-data# frozen_string_literal: true if defined?(Gem::VERSION) && Gem::VERSION >= "2.0." require File.expand_path(File.dirname(__FILE__) + '/yard/rubygems/hook') else unless 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 end yard-0.9.12/lib/yard/0000755000004100000410000000000013206751010014272 5ustar www-datawww-datayard-0.9.12/lib/yard/tags/0000755000004100000410000000000013206751010015230 5ustar www-datawww-datayard-0.9.12/lib/yard/tags/types_explainer.rb0000755000004100000410000001144213206751010020775 0ustar www-datawww-data# frozen_string_literal: true require 'strscan' module YARD module Tags class TypesExplainer # (see Tag#explain_types) # @param types [Array] a list of types to parse and summarize def self.explain(*types) explain!(*types) rescue SyntaxError nil end # (see explain) # @raise [SyntaxError] if the types are not parseable def self.explain!(*types) Parser.parse(types.join(", ")).join("; ") end class << self private :new end # @private class Type attr_accessor :name def initialize(name) @name = name end def to_s(singular = true) if name[0, 1] == "#" singular ? "an object that responds to #{name}" : "objects that respond to #{name}" elsif name[0, 1] =~ /[A-Z]/ singular ? "a#{name[0, 1] =~ /[aeiou]/i ? 'n' : ''} " + name : "#{name}#{name[-1, 1] =~ /[A-Z]/ ? "'" : ''}s" else name end end private def list_join(list) index = 0 list.inject(String.new) do |acc, el| acc << el.to_s acc << ", " if index < list.size - 2 acc << " or " if index == list.size - 2 index += 1 acc end end end # @private class CollectionType < Type attr_accessor :types def initialize(name, types) @name = name @types = types end def to_s(_singular = true) "a#{name[0, 1] =~ /[aeiou]/i ? 'n' : ''} #{name} of (" + list_join(types.map {|t| t.to_s(false) }) + ")" end end # @private class FixedCollectionType < CollectionType def to_s(_singular = true) "a#{name[0, 1] =~ /[aeiou]/i ? 'n' : ''} #{name} containing (" + types.map(&:to_s).join(" followed by ") + ")" end end # @private class HashCollectionType < Type attr_accessor :key_types, :value_types def initialize(name, key_types, value_types) @name = name @key_types = key_types @value_types = value_types end def to_s(_singular = true) "a#{name[0, 1] =~ /[aeiou]/i ? 'n' : ''} #{name} with keys made of (" + list_join(key_types.map {|t| t.to_s(false) }) + ") and values of (" + list_join(value_types.map {|t| t.to_s(false) }) + ")" end end # @private class Parser include CodeObjects TOKENS = { :collection_start => / />/, :fixed_collection_start => /\(/, :fixed_collection_end => /\)/, :type_name => /#{ISEP}#{METHODNAMEMATCH}|#{NAMESPACEMATCH}|\w+/, :type_next => /[,;]/, :whitespace => /\s+/, :hash_collection_start => /\{/, :hash_collection_next => /=>/, :hash_collection_end => /\}/, :parse_end => nil } def self.parse(string) new(string).parse end def initialize(string) @scanner = StringScanner.new(string) end def parse types = [] type = nil name = nil loop do found = false TOKENS.each do |token_type, match| # TODO: cleanup this code. # rubocop:disable Lint/AssignmentInCondition next unless (match.nil? && @scanner.eos?) || (match && token = @scanner.scan(match)) found = true case token_type when :type_name raise SyntaxError, "expecting END, got name '#{token}'" if name name = token when :type_next raise SyntaxError, "expecting name, got '#{token}' at #{@scanner.pos}" if name.nil? type = Type.new(name) unless type types << type type = nil name = nil when :fixed_collection_start, :collection_start name ||= "Array" klass = token_type == :collection_start ? CollectionType : FixedCollectionType type = klass.new(name, parse) when :hash_collection_start name ||= "Hash" type = HashCollectionType.new(name, parse, parse) when :hash_collection_next, :hash_collection_end, :fixed_collection_end, :collection_end, :parse_end raise SyntaxError, "expecting name, got '#{token}'" if name.nil? type = Type.new(name) unless type types << type return types end end raise SyntaxError, "invalid character at #{@scanner.peek(1)}" unless found end end end end end end yard-0.9.12/lib/yard/tags/tag_format_error.rb0000755000004100000410000000016213206751010021113 0ustar www-datawww-data# frozen_string_literal: true module YARD module Tags class TagFormatError < RuntimeError end end end yard-0.9.12/lib/yard/tags/default_tag.rb0000755000004100000410000000044213206751010020037 0ustar www-datawww-data# frozen_string_literal: true module 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 end yard-0.9.12/lib/yard/tags/option_tag.rb0000755000004100000410000000036113206751010017723 0ustar www-datawww-data# frozen_string_literal: true module 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.9.12/lib/yard/tags/directives.rb0000755000004100000410000005401513206751010017726 0ustar www-datawww-data# frozen_string_literal: true require '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? macro_data = find_or_create unless macro_data 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? if object && object.is_a?(CodeObjects::NamespaceObject) log.warn "Attaching macros to non-methods is unsupported, ignoring: " \ "#{object.path} (#{handler.parser.file}:#{handler.statement.line})" obj = nil else obj = object ? object : P("#{handler.namespace}.#{handler.caller_method}") end else obj = nil end return tag.text || "" if anonymous? # anonymous macro macro = CodeObjects::MacroObject.create(tag.name, tag.text, obj) 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 This directive should only be used if there is no explicit # declaration for the method in any source files (i.e., the method # is declared dynamically via meta-programming). In all other cases, add # documentation to the method definition itself. # @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) old_obj = parser.object parser.object = obj parser.post_process parser.object = old_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 a regular method, see {tag:!method} # # @note This directive should only be used if there is no explicit +attr_*+ # declaration for the attribute in any source files (i.e., the attribute # is declared dynamically via meta-programming). In all other cases, add # documentation to the attribute declaration itself. # @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] attrs[clean_name][:read] = object if readable? 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]] writer.docstring = object.base_docstring 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 end yard-0.9.12/lib/yard/tags/tag.rb0000755000004100000410000000511013206751010016330 0ustar www-datawww-data# frozen_string_literal: true module 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 = tag_name.to_s @text = text @name = name @types = (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 # Provides a plain English summary of the type specification, or nil # if no types are provided or parseable. # # @return [String] a plain English description of the associated types # @return [nil] if no types are provided or not parseable def explain_types return nil if !types || types.empty? TypesExplainer.explain(*types) end end end end yard-0.9.12/lib/yard/tags/ref_tag.rb0000755000004100000410000000016713206751010017173 0ustar www-datawww-data# frozen_string_literal: true module YARD module Tags module RefTag attr_accessor :owner end end end yard-0.9.12/lib/yard/tags/library.rb0000755000004100000410000006205613206751010017235 0ustar www-datawww-data# frozen_string_literal: true module 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 # # @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__ + 1) def #{tag_meth}(text) #{meth}.new(#{tag.inspect}, text) end eof else class_eval(<<-eof, __FILE__, __LINE__ + 1) begin; undef #{tag_meth}; rescue NameError; end 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? directive_class = tag_meth tag_meth = nil 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.tr('.', '_')}_#{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) @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 immediately 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. # # @note For keyword parameters, use +@param+, not +@option+. # # @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 key [Symbol] describe key param # # @param value [Object] describe value param # # @overload set(value) # # Sets a value on the default key +:foo+ # # @param value [Object] 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 (either regular or keyword) with a given name, type # and optional description. # # @example # # @param url [String] the URL of the page to download # # @param directory [String] the name of the directory to save to # def load_page(url, directory: 'pages') 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.9.12/lib/yard/tags/ref_tag_list.rb0000755000004100000410000000117013206751010020221 0ustar www-datawww-data# frozen_string_literal: true module 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 end yard-0.9.12/lib/yard/tags/overload_tag.rb0000755000004100000410000000377513206751010020242 0ustar www-datawww-data# frozen_string_literal: true module 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 ||= String.new("") 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 = $1 args = $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 = args.map do |a| k, v = *a.split(/:|=/, 2) [k.strip.to_s + (a[k.size, 1] == ':' ? ':' : ''), (v ? v.strip : nil)] end if args @name = meth.to_sym @parameters = args end end end end end yard-0.9.12/lib/yard/tags/default_factory.rb0000755000004100000410000001616413206751010020743 0ustar www-datawww-data# frozen_string_literal: true module 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 = name desc = 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 = TYPELIST_OPENING_CHARS.delete('(') close = TYPELIST_CLOSING_CHARS.delete(')') name, types, text = *extract_types_and_name_from_text(text, open, close) name, text = *extract_name_from_text(text) unless name if text && text.start_with?('(') _, 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 = nil desc = 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(&:strip), text.strip] end end def extract_types_and_name_from_text_unstripped(text, opening_types = TYPELIST_OPENING_CHARS, closing_types = TYPELIST_CLOSING_CHARS) e = 0 before = String.new("") list = [String.new("")] level = 0 seen_space = false i = 0 last_seen = '' while i < text.length c = text[i, 1] if (c == '"' || c == "'") && text[i..-1] =~ /#{c}.+?#{c}/ list.last << $& i += $&.length next end 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 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 String.new("") elsif c =~ /\S/ && level == 0 break e = i if seen_space && list == [''] before << c elsif c =~ /[ \t]/ && level == 0 && !before.empty? seen_space = true elsif level >= 1 list.last << c elsif level == 0 && c == "\n" break e = i 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 end yard-0.9.12/lib/yard/registry_resolver.rb0000755000004100000410000001413013206751010020412 0ustar www-datawww-data# frozen_string_literal: true module YARD # Handles all logic for complex lexical and inherited object resolution. # Used by {Registry.resolve}, so there is no need to use this class # directly. # # @see Registry.resolve # @since 0.9.1 class RegistryResolver include CodeObjects::NamespaceMapper # Creates a new resolver object for a registry. # # @param registry [Registry] only set this if customizing the registry # object def initialize(registry = Registry) @registry = registry @default_sep = nil end # Performs a lookup on a given path in the registry. Resolution will occur # in a similar way to standard Ruby identifier resolution, doing lexical # lookup, as well as (optionally) through the inheritance chain. A proxy # object can be returned if the lookup fails for future resolution. The # proxy will be type hinted with the +type+ used in the original lookup. # # @option opts namespace [CodeObjects::Base, :root, nil] (nil) the namespace # object to start searching from. If root or nil is provided, {Registry.root} # is assumed. # @option opts inheritance [Boolean] (false) whether to perform lookups through # the inheritance chain (includes mixins) # @option opts proxy_fallback [Boolean] (false) when true, a proxy is returned # if no match is found # @option opts type [Symbol] (nil) an optional type hint for the resolver # to consider when performing a lookup. If a type is provided and the # resolved object's type does not match the hint, the object is discarded. # @return [CodeObjects::Base, CodeObjects::Proxy, nil] the first object # that matches the path lookup. If proxy_fallback is provided, a proxy # object will be returned in the event of no match, otherwise nil will # be returned. # @example A lookup from root # resolver.lookup_by_path("A::B::C") # @example A lookup from the A::B namespace # resolver.lookup_by_path("C", namespace: P("A::B")) # @example A lookup on a method through the inheritance tree # resolver.lookup_by_math("A::B#foo", inheritance: true) def lookup_by_path(path, opts = {}) path = path.to_s namespace = opts[:namespace] inheritance = opts[:inheritance] || false proxy_fallback = opts[:proxy_fallback] || false type = opts[:type] if namespace.is_a?(CodeObjects::Proxy) return proxy_fallback ? CodeObjects::Proxy.new(namespace, path, type) : nil end if namespace == :root || !namespace namespace = @registry.root else namespace = namespace.parent until namespace.is_a?(CodeObjects::NamespaceObject) end orignamespace = namespace if path =~ /\A#{default_separator}/ path = $' namespace = @registry.root orignamespace = @registry.root end resolved = nil lexical_lookup = 0 while namespace && !resolved resolved = lookup_path_direct(namespace, path, type) resolved ||= lookup_path_inherited(namespace, path, type) if inheritance break if resolved namespace = namespace.parent lexical_lookup += 1 end # method objects cannot be resolved through lexical lookup by more than 1 ns if lexical_lookup > 1 && resolved.is_a?(CodeObjects::MethodObject) resolved = nil end if proxy_fallback resolved ||= CodeObjects::Proxy.new(orignamespace, path, type) end resolved end private # return [Boolean] if the obj's type matches the provided type. def validate(obj, type) !type || (obj && obj.type == type) ? obj : nil end # Performs a lexical lookup from a namespace for a path and a type hint. def lookup_path_direct(namespace, path, type) result = namespace.root? && validate(@registry.at(path), type) return result if result if path =~ /\A(#{separators_match})/ return validate(@registry.at(namespace.path + path), type) end separators.each do |sep| result = validate(@registry.at(namespace.path + sep + path), type) return result if result end nil end # Performs a lookup through the inheritance chain on a path with a type hint. def lookup_path_inherited(namespace, path, type) resolved = nil last_obj = namespace scopes = [] last_sep = nil pos = 0 if path =~ /\A(#{separators_match})/ last_sep = $1 path = $' end path.scan(/(.+?)(#{separators_match}|$)/).each do |part, sep| cur_obj = nil pos += "#{part}#{sep}".length parsed_end = pos == path.length if !last_obj || (!parsed_end && !last_obj.is_a?(CodeObjects::NamespaceObject)) break # can't continue end collect_namespaces(last_obj).each do |ns| next if ns.is_a?(CodeObjects::Proxy) found = nil search_seps = [] scopes.each do |scope| search_seps += separators_for_type(scope) end if search_seps.empty? search_seps = if ns.type == :root [""] elsif last_sep.nil? separators else [@default_sep] end end ([last_sep] | search_seps).compact.each do |search_sep| found = @registry.at(ns.path + search_sep.to_s + part) break if found end break cur_obj = found if found end last_sep = sep scopes = types_for_separator(sep) || [] last_obj = cur_obj resolved = cur_obj if parsed_end && cur_obj && (type.nil? || type == cur_obj.type) end resolved end # Collects and returns all inherited namespaces for a given object def collect_namespaces(object) return [] unless object.respond_to?(:inheritance_tree) nss = object.inheritance_tree(true) if object.respond_to?(:superclass) nss |= [P('Object')] if object.superclass != P('BasicObject') nss |= [P('BasicObject')] end nss end end end yard-0.9.12/lib/yard/registry_store.rb0000755000004100000410000002271013206751010017710 0ustar www-datawww-data# frozen_string_literal: true require '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] obj = @serializer.deserialize(key) if obj @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) initialize @file = file @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(&:size).each do |path| obj = @serializer.deserialize(path, true) objects << obj if obj 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 write_complete_lock true end # (see Serializers::YardocSerializer#lock_for_writing) # @param file [String] if supplied, the path to the database def lock_for_writing(file = nil, &block) Serializers::YardocSerializer.new(file || @file).lock_for_writing(&block) end # (see Serializers::YardocSerializer#locked_for_writing?) # @param file [String] if supplied, the path to the database def locked_for_writing?(file = nil) Serializers::YardocSerializer.new(file || @file).locked_for_writing? 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 root = @serializer.deserialize('root') return if root.nil? @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 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 def write_complete_lock File.open!(@serializer.complete_lock_path, 'w') {} end end end yard-0.9.12/lib/yard/core_ext/0000755000004100000410000000000013206751010016102 5ustar www-datawww-datayard-0.9.12/lib/yard/core_ext/string.rb0000755000004100000410000000313613206751010017743 0ustar www-datawww-data# frozen_string_literal: true class 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 = [String.new("")] state = :none escape_next = false quote = String.new("") strip.split(//).each do |char| case state when :none, :space case char when /\s/ out << String.new("") 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 = String.new("") 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.9.12/lib/yard/core_ext/hash.rb0000755000004100000410000000052413206751010017356 0ustar www-datawww-data# frozen_string_literal: true class 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.9.12/lib/yard/core_ext/module.rb0000755000004100000410000000103013206751010017711 0ustar www-datawww-data# frozen_string_literal: true class 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 end yard-0.9.12/lib/yard/core_ext/file.rb0000755000004100000410000000410313206751010017347 0ustar www-datawww-data# frozen_string_literal: true require '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 # @param [Boolean] rel_root allows relative path above root value # @return [String] the sanitized path def self.cleanpath(path, rel_root = false) path = path.split(SEPARATOR) path = path.inject([]) do |acc, comp| next acc if comp == RELATIVE_SAMEDIR if comp == RELATIVE_PARENTDIR && !acc.empty? && acc.last != RELATIVE_PARENTDIR acc.pop next acc elsif !rel_root && comp == RELATIVE_PARENTDIR && acc.empty? 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', &:read) end end yard-0.9.12/lib/yard/core_ext/insertion.rb0000755000004100000410000000375713206751010020460 0ustar www-datawww-data# frozen_string_literal: true # 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 = list @values = (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 index = list.index(val) list[index + rel, 0] = @values if index list end end yard-0.9.12/lib/yard/core_ext/array.rb0000755000004100000410000000113613206751010017551 0ustar www-datawww-data# frozen_string_literal: true class 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.9.12/lib/yard/core_ext/symbol_hash.rb0000755000004100000410000000477413206751010020756 0ustar www-datawww-data# frozen_string_literal: true # 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 key?(key) super(key.to_sym) end alias has_key? key? # 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 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.9.12/lib/yard/handlers/0000755000004100000410000000000013206751010016072 5ustar www-datawww-datayard-0.9.12/lib/yard/handlers/c/0000755000004100000410000000000013206751010016314 5ustar www-datawww-datayard-0.9.12/lib/yard/handlers/c/path_handler.rb0000755000004100000410000000045113206751010021275 0ustar www-datawww-data# frozen_string_literal: true class 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.9.12/lib/yard/handlers/c/mixin_handler.rb0000755000004100000410000000114613206751010021467 0ustar www-datawww-data# frozen_string_literal: true class 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) var = namespace_for_variable(mixin_var) if var namespace.mixins(:instance) << var else raise YARD::Parser::UndocumentableError, "CRuby mixin for unrecognized variable '#{mixin_var}'" end end end end yard-0.9.12/lib/yard/handlers/c/attribute_handler.rb0000755000004100000410000000071013206751010022342 0ustar www-datawww-data# frozen_string_literal: true class YARD::Handlers::C::AttributeHandler < YARD::Handlers::C::Base MATCH = /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.9.12/lib/yard/handlers/c/init_handler.rb0000755000004100000410000000110513206751010021301 0ustar www-datawww-data# frozen_string_literal: true # Handles the Init_Libname() method class YARD::Handlers::C::InitHandler < YARD::Handlers::C::Base MATCH = /\A\s*(?:\S+\s+)*void\s+(?:[Ii]nit_)?(\w+)\s*/ handles MATCH statement_class ToplevelStatement process do parse_block decl = statement.declaration[MATCH, 1] if decl 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.9.12/lib/yard/handlers/c/class_handler.rb0000755000004100000410000000147013206751010021450 0ustar www-datawww-data# frozen_string_literal: true class 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.strip, in_module) end end end yard-0.9.12/lib/yard/handlers/c/method_handler.rb0000755000004100000410000000231213206751010021617 0ustar www-datawww-data# frozen_string_literal: true class YARD::Handlers::C::MethodHandler < YARD::Handlers::C::Base MATCH1 = /rb_define_ ( singleton_method | method | module_function | private_method ) \s*\(\s*([\w\.]+)\s*, \s*"([^"]+)"\s*, \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\(|\(\w+\))?(\w+)\)?\s*, \s*(-?\w+)\s*\)/xm MATCH2 = /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.9.12/lib/yard/handlers/c/struct_handler.rb0000755000004100000410000000062413206751010021667 0ustar www-datawww-data# frozen_string_literal: true class 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.9.12/lib/yard/handlers/c/module_handler.rb0000755000004100000410000000111513206751010021624 0ustar www-datawww-data# frozen_string_literal: true class 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.9.12/lib/yard/handlers/c/alias_handler.rb0000755000004100000410000000072413206751010021435 0ustar www-datawww-data# frozen_string_literal: true class YARD::Handlers::C::AliasHandler < YARD::Handlers::C::Base MATCH = /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.9.12/lib/yard/handlers/c/handler_methods.rb0000755000004100000410000002045513206751010022012 0ustar www-datawww-data# frozen_string_literal: true module 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 ? ensure_variable_defined!(in_module) : Registry.root if namespace.nil? raise Parser::UndocumentableError, "class #{class_name}. Cannot find definition for parent namespace." end 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 ? ensure_variable_defined!(in_module) : Registry.root if namespace.nil? raise Parser::UndocumentableError, "module #{module_name}. Cannot find definition for parent namespace." end 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) # Is this method being defined on a core Ruby class or module? if namespace.is_a?(Proxy) if var_name =~ /^rb_c(\w+)/ && YARD::CodeObjects::BUILTIN_CLASSES.include?($1) namespace = namespaces[var_name] = YARD::CodeObjects::ClassObject.new(:root, $1) elsif var_name =~ /^rb_m(\w+)/ && YARD::CodeObjects::BUILTIN_MODULES.include?($1) namespace = namespaces[var_name] = YARD::CodeObjects::ModuleObject.new(:root, $1) end end 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.explicit = true 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) register_file_info(obj, statement.file, statement.line) 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 = new_name.to_sym old_meth = 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$|^global_const$/ namespace = type == 'global_const' ? :root : 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 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 = statement.file in_file = false if statement.comments && statement.comments.source =~ /\A\s*in (\S+)\Z/ file = $1 in_file = true process_file(file, object) end src_stmt = symbols[symbol] if src_stmt register_file_info(object, src_stmt.file, src_stmt.line, true) register_source(object, src_stmt) record_parameters(object, symbol, 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 return if override_comments.any? do |name, override_comment| next unless override_comment.file == file name = name.gsub(/::([^:\.#]+?)\Z/, '.\1') # explicit namespace in override comment path = (name =~ /\.|#/ ? object.path : object.name.to_s) if path == name || path == name.sub(/new$/, 'initialize') || path == name.sub('.', '#') register_docstring(object, override_comment.source, override_comment) true else false 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 def record_parameters(object, symbol, src) # use regex to extract comma-delimited list of parameters from cfunc definition if src.source =~ /VALUE\s+#{symbol}\(([^)]*)\)\s*\{/m params = $~[1].split(/\s*,\s*/) # rubocop:disable Style/SpecialGlobalVars # cfunc for a "varargs" method has params "int argc, VALUE *argv" if params[0] =~ /int\s+argc/ && params[1] =~ /VALUE\s*\*\s*argv/ object.parameters = [['*args', nil]] else # the first cfunc argument is the 'self' argument, we don't need that object.parameters = params.drop(1).map {|s| [s[/VALUE\s+(\S+)/, 1], nil] } end end end end end end end yard-0.9.12/lib/yard/handlers/c/override_comment_handler.rb0000755000004100000410000000155713206751010023712 0ustar www-datawww-data# frozen_string_literal: true # Parses comments class YARD::Handlers::C::OverrideCommentHandler < YARD::Handlers::C::Base handles(/./) 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.9.12/lib/yard/handlers/c/constant_handler.rb0000755000004100000410000000067013206751010022175 0ustar www-datawww-data# frozen_string_literal: true class YARD::Handlers::C::ConstantHandler < YARD::Handlers::C::Base MATCH = /\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.9.12/lib/yard/handlers/c/base.rb0000755000004100000410000000710013206751010017554 0ustar www-datawww-data# frozen_string_literal: true module 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 src = statement.respond_to?(:declaration) ? statement.declaration : statement.source 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) if type @statement_class = type else (defined?(@statement_class) && @statement_class) || Statement end 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 ensure_variable_defined!(var, max_retries = 1) retries = 0 object = nil loop do object = namespace_for_variable(var) break unless object.is_a?(Proxy) raise NamespaceMissingError, object if retries > max_retries log.debug "Missing namespace variable #{var} in file `#{parser.file}', moving it to the back of the line." parser.parse_remaining_files retries += 1 end object 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.9.12/lib/yard/handlers/c/symbol_handler.rb0000755000004100000410000000055113206751010021647 0ustar www-datawww-data# frozen_string_literal: true # Keeps track of function bodies for symbol lookup during Ruby method declarations class YARD::Handlers::C::SymbolHandler < YARD::Handlers::C::Base MATCH = /\A\s*(?:(?:\w+)\s+)?(?:intern\s+)?VALUE\s+(\w+)\s*\(/ handles MATCH statement_class ToplevelStatement process { symbols[statement.source[MATCH, 1]] = statement } end yard-0.9.12/lib/yard/handlers/processor.rb0000755000004100000410000001726513206751010020454 0ustar www-datawww-data# frozen_string_literal: true require '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 log.debug "#{handler} 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.\n" \ "If this class/method is part of your source tree, this will affect your documentation results.\n" \ "You can correct this issue by loading the source file for this object before `#{file}'\n" rescue Parser::UndocumentableError => undocerr log.warn "in #{handler}: Undocumentable #{undocerr.message}\n" \ "\tin file '#{file}':#{stmt.line}:\n\n" + stmt.show + "\n" rescue => e log.error "Unhandled exception in #{handler}:\n" \ " 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 end yard-0.9.12/lib/yard/handlers/base.rb0000755000004100000410000005464113206751010017346 0ustar www-datawww-data# frozen_string_literal: true module 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 ||= []).concat(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) # rubocop:disable Lint/UnusedMethodArgument 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 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(*) 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}. # # @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 = {}) opts = { :namespace => namespace, :scope => :instance, :owner => owner || namespace, :visibility => nil }.update(opts) ns = namespace vis = visibility sc = scope oo = 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) ensure_loaded!(object.namespace) object.namespace.children << object rescue NamespaceMissingError nil # noop 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 && !object.namespace.is_a?(Proxy) Tags::Library.transitive_tags.each do |tag| 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 # rubocop:disable Lint/UselessSetterCall 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) raise NamespaceMissingError, object 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 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.9.12/lib/yard/handlers/ruby/0000755000004100000410000000000013206751010017053 5ustar www-datawww-datayard-0.9.12/lib/yard/handlers/ruby/module_function_handler.rb0000755000004100000410000000157313206751010024300 0ustar www-datawww-data# frozen_string_literal: true # 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 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.9.12/lib/yard/handlers/ruby/dsl_handler_methods.rb0000755000004100000410000000556613206751010023421 0ustar www-datawww-data# frozen_string_literal: true module 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) attaching = false if @docstring =~ /^@!?macro\s+\[[^\]]*attach/ register_docstring(nil) @docstring = "" attaching = true end macro = find_attached_macro if macro txt = macro.expand([caller_method, *call_params], statement.source) @docstring += "\n" + txt # macro may have a directive return register_docstring(nil) if !attaching && txt.match(/^\s*@!/) 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_name_matches(macro) (namespace.inheritance_tree(true) + [P('Object')]).each do |obj| return macro if obj == macro.method_object.namespace end end nil end # @return [Boolean] whether caller method matches a macro or # its alias names. def macro_name_matches(macro) objs = [macro.method_object] if objs.first.type != :proxy && objs.first.respond_to?(:aliases) objs.concat(objs.first.aliases) end objs.any? {|obj| obj.name.to_s == caller_method.to_s } end end end end end yard-0.9.12/lib/yard/handlers/ruby/decorator_handler_methods.rb0000755000004100000410000000774013206751010024615 0ustar www-datawww-data# frozen_string_literal: true # Helper methods to assist with processing decorators. module YARD::Handlers::Ruby::DecoratorHandlerMethods # @overload process_decorator(*nodes, opts = {}, &block) # Takes care of parsing method definitions passed to decorators # as parameters, as well as parsing chained decorators. # # Use this in a handler's process block. # # @yieldparam method [YARD::CodeObjects::MethodObject] Method being decorated. # @yieldparam node [YARD::Parser::Ruby::AstNode] AST node of the decorated method. # @yieldparam name [Symbol] Name of the decorated method. # @return [Array] Array of hashes containing :method, :node, :name. # See yield params. # # @param nodes [YARD::Parser::Ruby::AstNode] AST nodes that refer to decorated # methods, like indexes of statement.parameter. Defaults to all parameters. # Pass nil to specify zero parameters. # # @option opts [:instance, :class] :scope (:instance) Scope to use for each # MethodObject. # # @option opts [true, false] :transfer_docstring Set false to disable # transferring the decorator docstring to method definitions passed to the # decorator as parameters. # # @option opts [true, false] :transfer_source Set false to disable # transferring the decorator source code string to method definitions # passed to the decorator as parameters. # # @example Basic Usage # # Simply pass the method docs through to the method definition. # process do # process_decorator # end # # @example Setting a method's visibility to private. # process do # process_decorator :scope => :class do |method| # method.visibility = :private if method.respond_to? :visibility # end # end def process_decorator(*nodes, &block) opts = nodes.last.is_a?(Hash) ? nodes.pop : {} all_nodes = statement.parameters.select do |p| p.is_a? YARD::Parser::Ruby::AstNode end # Parse decorator parameters (decorator chain). all_nodes.each do |param| parse_block param if param.call? || param.def? end selected_nodes = if nodes.empty? all_nodes elsif nodes.count == 1 && nodes.first.nil? [] else nodes end decorated_methods = selected_nodes.map do |param| process_decorator_parameter param, opts, &block end.flatten # Store method nodes in decorator node. statement.define_singleton_method :decorators do decorated_methods.map {|h| h[:node] } end decorated_methods end private def process_decorator_parameter(node, opts = {}, &block) scope = opts.fetch :scope, :instance transfer_docstring = opts.fetch :transfer_docstring, true transfer_source = opts.fetch :transfer_source, true name = nil if node.call? if node.respond_to? :decorators return node.decorators.map do |n| process_decorator_parameter n, opts, &block end end elsif node.def? name = node.jump(:def).method_name.source else name = node.jump(:ident, :string_content, :const).source end if name.nil? raise YARD::Parser::UndocumentableError, 'statement, cannot determine method name' end method = YARD::CodeObjects::Proxy.new( namespace, (scope == :instance ? '#' : '.') + name.to_s, :method ) # Transfer source to methods passed to the helper as parameters. method.source = statement.source if transfer_source && node.def? # Transfer decorator docstring to methods passed to the helper as parameters. if transfer_docstring && node.def? && statement.docstring && method.docstring.empty? tags = method.tags if method.respond_to? :tags tags ||= [] method.docstring = statement.docstring tags.each {|t| method.add_tag t } end yield method, node, name.to_sym if block_given? [{:method => method, :node => node, :name => name.to_sym}] end end yard-0.9.12/lib/yard/handlers/ruby/mixin_handler.rb0000755000004100000410000000225113206751010022224 0ustar www-datawww-data# frozen_string_literal: true # 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 unless errors.empty? 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.9.12/lib/yard/handlers/ruby/extend_handler.rb0000755000004100000410000000105713206751010022372 0ustar www-datawww-data# frozen_string_literal: true # 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.9.12/lib/yard/handlers/ruby/legacy/0000755000004100000410000000000013206751010020317 5ustar www-datawww-datayard-0.9.12/lib/yard/handlers/ruby/legacy/module_function_handler.rb0000755000004100000410000000114313206751010025535 0ustar www-datawww-data# frozen_string_literal: true # (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.9.12/lib/yard/handlers/ruby/legacy/mixin_handler.rb0000755000004100000410000000222013206751010023464 0ustar www-datawww-data# frozen_string_literal: true # (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 unless errors.empty? 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) mixmatch = mixin[/\A(#{NAMESPACEMATCH})/, 1] raise YARD::Parser::UndocumentableError unless mixmatch 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.9.12/lib/yard/handlers/ruby/legacy/extend_handler.rb0000755000004100000410000000074513206751010023641 0ustar www-datawww-data# frozen_string_literal: true # (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.9.12/lib/yard/handlers/ruby/legacy/attribute_handler.rb0000755000004100000410000000417613206751010024357 0ustar www-datawww-data# frozen_string_literal: true # (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 = true write = 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 = false write = 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 else obj = namespace.children.find {|other| other.name == meth.to_sym && other.scope == scope } # register an existing method as attribute namespace.attributes[scope][name][type] = obj if obj end end end end end yard-0.9.12/lib/yard/handlers/ruby/legacy/class_handler.rb0000755000004100000410000000741313206751010023456 0ustar www-datawww-data# frozen_string_literal: true # (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) match = superclass.match(/\A(Struct)\.new\((.*?)\)/) if match 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 end yard-0.9.12/lib/yard/handlers/ruby/legacy/visibility_handler.rb0000755000004100000410000000100013206751010024522 0ustar www-datawww-data# frozen_string_literal: true # (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 end yard-0.9.12/lib/yard/handlers/ruby/legacy/class_condition_handler.rb0000755000004100000410000000440713206751010025524 0ustar www-datawww-data# frozen_string_literal: true # (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 unless 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| next unless TkELSE === stmt.tokens.first push_state(:visibility => visibility) do parser.process(stmtlist.new(stmt.block)) end end end end yard-0.9.12/lib/yard/handlers/ruby/legacy/method_handler.rb0000755000004100000410000000553113206751010023630 0ustar www-datawww-data# frozen_string_literal: true # (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 = $1 args = $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 = :class meth = $1 prefix = $` 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 info = obj.attr_info if info if meth.to_s =~ /=$/ # writer info[:write] = obj if info[:read] elsif info[:write] info[:read] = obj end end parse_block(:owner => obj) # mainly for yield/exceptions end end yard-0.9.12/lib/yard/handlers/ruby/legacy/module_handler.rb0000755000004100000410000000056013206751010023632 0ustar www-datawww-data# frozen_string_literal: true # (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 end yard-0.9.12/lib/yard/handlers/ruby/legacy/class_variable_handler.rb0000755000004100000410000000067513206751010025326 0ustar www-datawww-data# frozen_string_literal: true # (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 end yard-0.9.12/lib/yard/handlers/ruby/legacy/yield_handler.rb0000755000004100000410000000203613206751010023453 0ustar www-datawww-data# frozen_string_literal: true # (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.9.12/lib/yard/handlers/ruby/legacy/alias_handler.rb0000755000004100000410000000261413206751010023440 0ustar www-datawww-data# frozen_string_literal: true # (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.delete('"') : n } new_meth = names[0].to_sym old_meth = 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 end yard-0.9.12/lib/yard/handlers/ruby/legacy/dsl_handler.rb0000755000004100000410000000055113206751010023127 0ustar www-datawww-data# frozen_string_literal: true module 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.9.12/lib/yard/handlers/ruby/legacy/exception_handler.rb0000755000004100000410000000077413206751010024352 0ustar www-datawww-data# frozen_string_literal: true # (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.9.12/lib/yard/handlers/ruby/legacy/constant_handler.rb0000755000004100000410000000161413206751010024177 0ustar www-datawww-data# frozen_string_literal: true # (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(&:to_s) end end yard-0.9.12/lib/yard/handlers/ruby/legacy/comment_handler.rb0000755000004100000410000000035413206751010024010 0ustar www-datawww-data# frozen_string_literal: true # (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.9.12/lib/yard/handlers/ruby/legacy/base.rb0000755000004100000410000002230513206751010021563 0ustar www-datawww-data# frozen_string_literal: true module 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(&:first) else tokens = statement.tokens[1..-1] tokval_list(tokens, :attr, :identifier, TkId).map(&:to_s) 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 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 = $1 args = $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 meth = $` if meth =~ /(?:#{NSEPQ}|#{CSEPQ})([^#{NSEP}#{CSEPQ}]+)$/ [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 =~ %r{\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 = 0 beforeparen = 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 elsif parencond out.last << token.text 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 unless tokval.nil? when TkRBRACE, TkRBRACK, TkEND out.last << token.text unless 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 break if beforeparen == 0 && parencount < 0 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 end yard-0.9.12/lib/yard/handlers/ruby/legacy/private_constant_handler.rb0000755000004100000410000000116113206751010025726 0ustar www-datawww-data# frozen_string_literal: true # (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.9.12/lib/yard/handlers/ruby/legacy/private_class_method_handler.rb0000755000004100000410000000121013206751010026535 0ustar www-datawww-data# frozen_string_literal: true # (see Ruby::PrivateClassMethodHandler) class YARD::Handlers::Ruby::Legacy::PrivateClassMethodHandler < YARD::Handlers::Ruby::Legacy::Base handles(/\Aprivate_class_method(\s|\(|$)/) namespace_only process do tokval_list(statement.tokens[2..-1], :attr).each do |name| privatize_class_method name end end private def privatize_class_method(name) method = Proxy.new(namespace, name) ensure_loaded!(method) method.visibility = :private rescue YARD::Handlers::NamespaceMissingError raise UndocumentableError, "private visibility set on unrecognized method: #{name}" end end yard-0.9.12/lib/yard/handlers/ruby/method_condition_handler.rb0000755000004100000410000000040413206751010024424 0ustar www-datawww-data# frozen_string_literal: true # 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 end yard-0.9.12/lib/yard/handlers/ruby/struct_handler_methods.rb0000755000004100000410000001534413206751010024156 0ustar www-datawww-data# frozen_string_literal: true # 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(&: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 !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| next if klass.attributes[:instance][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.9.12/lib/yard/handlers/ruby/attribute_handler.rb0000755000004100000410000000546713206751010023117 0ustar www-datawww-data# frozen_string_literal: true # 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 = true write = 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 = false write = 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 else obj = namespace.children.find {|other| other.name == meth.to_sym && other.scope == scope } # register an existing method as attribute namespace.attributes[scope][name][type] = obj if 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 end yard-0.9.12/lib/yard/handlers/ruby/class_handler.rb0000755000004100000410000001017213206751010022206 0ustar www-datawww-data# frozen_string_literal: true # 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 return superclass.parameters.first.source if methname == "DelegateClass" return methname if superclass.method_name.type == :const when :call, :command_call cname = superclass.namespace.source if cname =~ /^O?Struct$/ && superclass.method_name(true) == :new return cname end end nil end end yard-0.9.12/lib/yard/handlers/ruby/visibility_handler.rb0000755000004100000410000000122613206751010023270 0ustar www-datawww-data# frozen_string_literal: true # Handles 'private', 'protected', and 'public' calls. class YARD::Handlers::Ruby::VisibilityHandler < YARD::Handlers::Ruby::Base include YARD::Handlers::Ruby::DecoratorHandlerMethods 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 process_decorator do |method| method.visibility = ident.first if method.respond_to? :visibility= end end end end yard-0.9.12/lib/yard/handlers/ruby/class_condition_handler.rb0000755000004100000410000000462413206751010024261 0ustar www-datawww-data# frozen_string_literal: true # 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 unless 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 end yard-0.9.12/lib/yard/handlers/ruby/method_handler.rb0000755000004100000410000000660013206751010022362 0ustar www-datawww-data# frozen_string_literal: true # 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 info = obj.attr_info if info if meth.to_s =~ /=$/ # writer info[:write] = obj if info[:read] elsif info[:write] info[:read] = obj end end parse_block(blk, :owner => obj) # mainly for yield/exceptions end def format_args args = statement.parameters params = [] if args.unnamed_required_params params += args.unnamed_required_params.map {|a| [a.source, nil] } end if args.unnamed_optional_params params += args.unnamed_optional_params.map do |a| [a[0].source, a[1].source] end end params << ['*' + args.splat_param.source, nil] if args.splat_param if args.unnamed_end_params params += args.unnamed_end_params.map {|a| [a.source, nil] } end if args.named_params params += args.named_params.map do |a| [a[0].source, a[1] ? a[1].source : nil] end end if args.double_splat_param params << ['**' + args.double_splat_param.source, nil] end 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.9.12/lib/yard/handlers/ruby/module_handler.rb0000755000004100000410000000052113206751010022363 0ustar www-datawww-data# frozen_string_literal: true # 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 end yard-0.9.12/lib/yard/handlers/ruby/class_variable_handler.rb0000755000004100000410000000073713206751010024061 0ustar www-datawww-data# frozen_string_literal: true # 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 end yard-0.9.12/lib/yard/handlers/ruby/yield_handler.rb0000755000004100000410000000206413206751010022210 0ustar www-datawww-data# frozen_string_literal: true # 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.9.12/lib/yard/handlers/ruby/alias_handler.rb0000755000004100000410000000305113206751010022170 0ustar www-datawww-data# frozen_string_literal: true # 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 = names[0].to_sym old_meth = 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 namespace.aliases[new_obj] = old_meth if old_obj new_obj.signature = old_obj.signature new_obj.source = old_obj.source comments = [old_obj.docstring.to_raw, statement.comments].join("\n") doc = YARD::Docstring.parser.parse(comments, new_obj, self) new_obj.docstring = doc.to_docstring 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 end end yard-0.9.12/lib/yard/handlers/ruby/public_class_method_handler.rb0000755000004100000410000000065413206751010025110 0ustar www-datawww-data# frozen_string_literal: true # Sets visibility of a class method to public. class YARD::Handlers::Ruby::PublicClassMethodHandler < YARD::Handlers::Ruby::Base include YARD::Handlers::Ruby::DecoratorHandlerMethods handles method_call(:public_class_method) namespace_only process do process_decorator :scope => :class do |method| method.visibility = :public if method.respond_to? :visibility end end end yard-0.9.12/lib/yard/handlers/ruby/dsl_handler.rb0000755000004100000410000000052413206751010021663 0ustar www-datawww-data# frozen_string_literal: true module 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.9.12/lib/yard/handlers/ruby/exception_handler.rb0000755000004100000410000000153113206751010023076 0ustar www-datawww-data# frozen_string_literal: true # 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.9.12/lib/yard/handlers/ruby/constant_handler.rb0000755000004100000410000000362013206751010022732 0ustar www-datawww-data# frozen_string_literal: true # 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) elsif statement[0].type == :const_path_field process_constant(statement) end end private def process_constant(statement) name = statement[0].source value = statement[1].source obj = P(namespace, name) if obj.is_a?(NamespaceObject) && obj.namespace == namespace raise YARD::Parser::UndocumentableError, "constant for existing #{obj.type} #{obj}" else ensure_loaded! obj.parent register ConstantObject.new(namespace, name) {|o| o.source = statement; o.value = value.strip } end 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])) parse_block(statement[1].block[1], :namespace => klass) unless statement[1].block.nil? 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.9.12/lib/yard/handlers/ruby/comment_handler.rb0000755000004100000410000000037613206751010022550 0ustar www-datawww-data# frozen_string_literal: true # 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.9.12/lib/yard/handlers/ruby/base.rb0000755000004100000410000001336013206751010020320 0ustar www-datawww-data# frozen_string_literal: true module 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) # rubocop:disable Lint/UnusedMethodArgument 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 end end end end end end yard-0.9.12/lib/yard/handlers/ruby/private_constant_handler.rb0000755000004100000410000000260213206751010024463 0ustar www-datawww-data# frozen_string_literal: true module YARD module Handlers module Ruby # Sets visibility of a constant (class, module, const) class 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 unless errors.empty? 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 end end end end yard-0.9.12/lib/yard/handlers/ruby/private_class_method_handler.rb0000755000004100000410000000066113206751010025302 0ustar www-datawww-data# frozen_string_literal: true # Sets visibility of a class method to private. class YARD::Handlers::Ruby::PrivateClassMethodHandler < YARD::Handlers::Ruby::Base include YARD::Handlers::Ruby::DecoratorHandlerMethods handles method_call(:private_class_method) namespace_only process do process_decorator :scope => :class do |method| method.visibility = :private if method.respond_to? :visibility= end end end yard-0.9.12/lib/yard/docstring.rb0000755000004100000410000003230613206751010016622 0ustar www-datawww-data# frozen_string_literal: true module 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_defined?("@#{name}") && 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 defined?(@summary) && @summary stripped = gsub(/[\r\n](?![\r\n])/, ' ').strip num_parens = 0 idx = length.times do |index| case stripped[index, 1] when "." next_char = stripped[index + 1, 1].to_s break index - 1 if num_parens <= 0 && next_char =~ /^\s*$/ when "\r", "\n" next_char = stripped[index + 1, 1].to_s if next_char =~ /^\s*$/ break stripped[index - 1, 1] == '.' ? index - 2 : 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(&: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(&: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 defined?(@unresolved_reference).nil? || @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 } @ref_tag_recurse_count ||= 0 @ref_tag_recurse_count += 1 if @ref_tag_recurse_count > 2 log.error "#{@object.file}:#{@object.line}: Detected circular reference tag in " \ "`#{@object}', ignoring all reference tags for this object " \ "(#{@ref_tags.map {|t| "@#{t.tag_name}" }.join(", ")})." @ref_tags = [] return @ref_tags end list = list.map(&:tags).flatten @ref_tag_recurse_count -= 1 list 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.9.12/lib/yard/templates/0000755000004100000410000000000013206751010016270 5ustar www-datawww-datayard-0.9.12/lib/yard/templates/template_options.rb0000755000004100000410000000715213206751010022213 0ustar www-datawww-data# frozen_string_literal: true require '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 # @return [Boolean] whether the page is the "index" attr_accessor :index # @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 true if mixin == object # the method is not inherited return nil unless mixin.is_a?(CodeObjects::ModuleObject) 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.9.12/lib/yard/templates/erb_cache.rb0000755000004100000410000000110713206751010020512 0ustar www-datawww-data# frozen_string_literal: true module YARD module Templates # @since 0.5.4 module ErbCache def self.method_for(filename) @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 defined?(@methods) && @methods @methods.clear end end end end yard-0.9.12/lib/yard/templates/section.rb0000755000004100000410000000452413206751010020271 0ustar www-datawww-data# frozen_string_literal: true module 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] : [] subsections = [] if subsections.is_a?(Section) sections << Section.new(name, subsections) end end sections end end end end yard-0.9.12/lib/yard/templates/engine.rb0000755000004100000410000001655213206751010020076 0ustar www-datawww-data# frozen_string_literal: true require '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) unless template_paths.include?(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; nil 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) 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.9.12/lib/yard/templates/helpers/0000755000004100000410000000000013206751010017732 5ustar www-datawww-datayard-0.9.12/lib/yard/templates/helpers/markup/0000755000004100000410000000000013206751010021231 5ustar www-datawww-datayard-0.9.12/lib/yard/templates/helpers/markup/rdoc_markdown.rb0000755000004100000410000000104113206751010024406 0ustar www-datawww-data# frozen_string_literal: true module YARD module Templates module Helpers module Markup begin require 'rdoc'; rescue LoadError; nil 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.9.12/lib/yard/templates/helpers/markup/rdoc_markup.rb0000755000004100000410000000625213206751010024074 0ustar www-datawww-data# frozen_string_literal: true require 'thread' module YARD module Templates module Helpers module Markup begin require 'rdoc'; rescue LoadError; nil 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) 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(%r{<(/)?(pre|code|tt)|(\s|^|>)\+(?! )([^\n\+]{1,900})(?! )\+}) do |str| closed = $1 tag = $2 first_text = $3 type_text = $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) # rubocop:disable Style/MethodName @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\.)/ ? true : false super end end end end end end yard-0.9.12/lib/yard/templates/helpers/html_syntax_highlight_helper.rb0000755000004100000410000000534513206751010026231 0ustar www-datawww-data# frozen_string_literal: true module YARD module Templates module Helpers # Helper methods for syntax highlighting. module HtmlSyntaxHighlightHelper include ModuleHelper # 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) resolver = Parser::Ruby::TokenResolver.new(source, object) output = String.new("") resolver.each do |s, token_obj| token_obj = clean_token_object(token_obj) output << "" if [:tstring_beg, :regexp_beg].include?(s[0]) case s.first when :nl, :ignored_nl, :sp output << h(s[1]) when :ident, :const klass = s.first == :ident ? "id identifier rubyid_#{h(s[1])}" : s.first val = token_obj ? link_object(token_obj, s[1]) : h(s[1]) output << "#{val}" 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 def clean_token_object(token_obj) return unless token_obj if token_obj == object token_obj = nil elsif token_obj.is_a?(CodeObjects::MethodObject) token_obj = prune_method_listing([token_obj], false).first else token_obj = run_verifier([token_obj]).first end token_obj end end end end end yard-0.9.12/lib/yard/templates/helpers/base_helper.rb0000755000004100000410000001577113206751010022546 0ustar www-datawww-data# frozen_string_literal: true module 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; (defined?(@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 obj = YARD::Registry.resolve(object.namespace, path) if obj link_include_object(obj) else log.warn "Cannot find object at `#{path}' for inclusion" "" end when /^render:(\S+)/ path = $1 obj = YARD::Registry.resolve(object, path) if obj 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) # rubocop:disable Lint/UnusedMethodArgument 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) # rubocop:disable Lint/UnusedMethodArgument 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.9.12/lib/yard/templates/helpers/html_helper.rb0000755000004100000410000005425413206751010022577 0ustar www-datawww-data# frozen_string_literal: true require 'cgi' module YARD module Templates::Helpers # The helper module for HTML templates. module HtmlHelper include MarkupHelper include HtmlSyntaxHighlightHelper # @private URLMATCH = /[^\w\s~!\*'\(\):;@&=\$,\[\]<>-]/ # @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) text = text.dup enc = nil if text.respond_to?(:force_encoding) enc = text.encoding text = text.force_encoding('binary') end text = text.gsub(/%[a-z0-9]{2}|#{URLMATCH}/i) do $&.size > 1 ? $& : "%" + $&.ord.to_s(16).upcase end.tr(' ', '+') text = text.force_encoding(enc) if enc text end module_function :urlencode # @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).dup 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, :tables, :lax_spacing).to_html else provider.new(text).to_html end end # Converts org-mode to HTML # @param [String] text input org-mode text # @return [String] output HTML def html_markup_org(text) markup_class(:org).new(text).to_html 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(%r{<(/)?(pre|code|tt)|(\\|!)?\{(?!\})(\S+?)(?:\s([^\}]*?\S))?\}(?=[\W<]|.+.*\s*(.*)\Z} name = $1 title = $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 = (defined?(@file) && @file ? @file.filename : object.file) || '(unknown)' line = (defined?(@file) && @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 ? ":" : ".") + "\n\t" + (match[1] ? '...' : '') + match[2].delete("\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) insert_include(file.contents, file.attributes[:markup] || options.markup) end # (see BaseHelper#link_include_object) def link_include_object(obj) insert_include(obj.docstring) end # Inserts an include link while respecting inlining def insert_include(text, markup = options.markup) htmlify(text, markup).gsub(%r{\A\s*

            |

            \s*\Z}, '') 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.title) 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 = title.gsub(/[\r\n]/, ' ') params = SymbolHash.new(false).update( :href => url, :title => h(title) ).update(params) params[:target] ||= '_parent' if url =~ %r{^(\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 relative = false if object == Registry.root 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 alias mtime_url url_for def mtime(_file) nil 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) path = filename == options.readme ? 'index.html' : serializer.serialized_path(filename) 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) type = "⇒ #{type}" if type && !type.empty? 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 rw = meth.attr_info if rw 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, h(name), args, blk, type] 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 defined?(@file) && @file && has_encoding lang = @file.contents.encoding.to_s else return 'utf-8' unless has_encoding || ENV['LANG'] lang = if has_encoding ::Encoding.default_external.name.downcase else ENV['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 = $1 source = $' 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(%r{(?:\s*)?(.+?)(?:
            \s*)?}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(' ') %(
            #{string}
            ) end end end end end yard-0.9.12/lib/yard/templates/helpers/uml_helper.rb0000755000004100000410000000267113206751010022424 0ustar www-datawww-data# frozen_string_literal: true module 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 end yard-0.9.12/lib/yard/templates/helpers/markup_helper.rb0000755000004100000410000001463713206751010023133 0ustar www-datawww-data# frozen_string_literal: true require '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'} ], :org => [ {:lib => :'org-ruby', :const => 'Orgmode::Parser'} ], :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'], :org => ['org'], :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 # rubocop:disable Lint/Eval 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 lib = 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) return $1.to_sym if contents && contents =~ MARKUP_FILE_SHEBANG # Shebang support 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.9.12/lib/yard/templates/helpers/filter_helper.rb0000755000004100000410000000131313206751010023104 0ustar www-datawww-data# frozen_string_literal: true module 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.9.12/lib/yard/templates/helpers/text_helper.rb0000755000004100000410000000753413206751010022616 0ustar www-datawww-data# frozen_string_literal: true module YARD module Templates module Helpers # Helper methods for text template formats. module TextHelper # @return [String] escapes text def h(text) out = String.new("") text = resolve_links(text) 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 = '' rw = meth.namespace.attributes[meth.scope][meth.name] if rw 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 private def resolve_links(text) text.gsub(/(\\|!)?\{(?!\})(\S+?)(?:\s([^\}]*?\S))?\}(?=[\W]|$)/m) do |_str| escape = $1 name = $2 title = $3 match = $& next(match[1..-1]) if escape next(match) if name[0, 1] == '|' linkify(name, title) end end end end end end yard-0.9.12/lib/yard/templates/helpers/module_helper.rb0000755000004100000410000000161013206751010023104 0ustar www-datawww-data# frozen_string_literal: true module 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| run_verifier([o.parent]).empty? } 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.9.12/lib/yard/templates/helpers/method_helper.rb0000755000004100000410000000471113206751010023104 0ustar www-datawww-data# frozen_string_literal: true module 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 if params.empty? "" else args = params.map do |n, v| v ? "#{n}#{n[-1, 1] == ':' ? '' : ' ='} #{v}" : n.to_s end.join(", ") h("(#{args})") 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(&: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.9.12/lib/yard/templates/template.rb0000755000004100000410000003345413206751010020444 0ustar www-datawww-data# frozen_string_literal: true require '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 do |options| {:html => Helpers::HtmlHelper, :text => Helpers::TextHelper, :dot => Helpers::UMLHelper}[options.format] end ] 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 # rubocop:disable Style/MethodName # Alias for creating {Engine.template}. 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 # rubocop:enable Style/MethodName 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) # rubocop:disable Style/MethodName 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) unless args.empty? @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 = String.new("") 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] sect if provided, uses a specific section name # @return [String] the rendered ERB file in any of the inherited template # paths. def superb(sect = section, &block) filename = self.class.find_nth_file(erb_file_for(sect), 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 sect = section value = yield self.section = sect value end end end end yard-0.9.12/lib/yard/rubygems/0000755000004100000410000000000013206751010016127 5ustar www-datawww-datayard-0.9.12/lib/yard/rubygems/hook.rb0000755000004100000410000001162313206751010017422 0ustar www-datawww-data# frozen_string_literal: true require 'rubygems' require 'rubygems/user_interaction' require 'fileutils' ## # Gem::YARDoc provides methods to generate YARDoc and yri data for installed gems # upon gem installation. # # This file is automatically required by RubyGems 1.9 and newer. module YARD class RubygemsHook include Gem::UserInteraction extend Gem::UserInteraction @yard_version = nil ## # Force installation of documentation? attr_accessor :force ## # Generate yard? attr_accessor :generate_yard ## # Generate yri data? attr_accessor :generate_yri class << self ## # Loaded version of YARD. Set by ::load_yard attr_reader :yard_version end ## # Post installs hook that generates documentation for each specification in # +specs+ def self.generation_hook(installer, specs) start = Time.now types = installer.document generate_yard = types.include?('yardoc') || types.include?('yard') generate_yri = types.include? 'yri' specs.each do |spec| gen_yard = generate_yard gen_yri = generate_yri gen_yri = false if gen_yard # never generate both, no need unless types.empty? # --no-document is not in effect # look at spec.metadata['yard.run'] for override run_yard = spec.metadata['yard.run'] gen_yard = true if run_yard && run_yard != 'yri' gen_yri = true if run_yard == 'yri' end new(spec, gen_yard, gen_yri).generate end return unless generate_yard || generate_yri duration = (Time.now - start).to_i names = specs.map(&:name).join ', ' say "Done installing documentation for #{names} after #{duration} seconds" end ## # Pre uninstalls hook that removes documentation # def self.removal_hook(uninstaller) new(uninstaller.spec).remove end ## # Loads the YARD generator def self.load_yard return if @yard_version require 'yard' @yard_version = Gem::Version.new ::YARD::VERSION end def initialize(spec, generate_yard = false, generate_yri = true) @doc_dir = spec.doc_dir @force = false @spec = spec @generate_yard = generate_yard @generate_yri = generate_yri @yard_dir = spec.doc_dir('yard') @yri_dir = spec.doc_dir('.yardoc') end def run_yardoc(*args) args << '--quiet' unless Gem.configuration.really_verbose args << '--backtrace' if Gem.configuration.backtrace unless File.file?(File.join(@spec.full_gem_path, '.yardopts')) args << @spec.require_paths unless @spec.extra_rdoc_files.empty? args << '-' args += @spec.extra_rdoc_files end end args = args.flatten.map(&:to_s) Dir.chdir(@spec.full_gem_path) do YARD::CLI::Yardoc.run(*args) end rescue Errno::EACCES => e dirname = File.dirname e.message.split("-")[1].strip raise Gem::FilePermissionError, 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)" end def install_yard FileUtils.rm_rf @yard_dir say "Installing YARD documentation for #{@spec.full_name}..." run_yardoc '--no-progress', '--db', @yri_dir, '-o', @yard_dir end def install_yri FileUtils.rm_rf @yri_dir say "Building YARD (yri) index for #{@spec.full_name}..." run_yardoc '--no-progress', '-c', '-n', '--db', @yri_dir end ## # Generates YARD and yri data def generate return if @spec.default_gem? return unless @generate_yri || @generate_yard setup install_yri if @generate_yri && (@force || !File.exist?(@yri_dir)) install_yard if @generate_yard && (@force || !File.exist?(@yard_dir)) end ## # Prepares the spec for documentation generation def setup self.class.load_yard if File.exist?(@doc_dir) raise Gem::FilePermissionError, @doc_dir unless File.writable?(@doc_dir) else FileUtils.mkdir_p @doc_dir end end def uninstall_yard if File.exist?(@yard_dir) raise Gem::FilePermissionError, @yard_dir unless File.writable?(@yard_dir) FileUtils.rm_rf @yard_dir end end def uninstall_yri if File.exist?(@yri_dir) raise Gem::FilePermissionError, @yri_dir unless File.writable?(@yri_dir) FileUtils.rm_rf @yri_dir end end ## # Removes YARD and yri data def remove uninstall_yri uninstall_yard end end end Gem.done_installing(&YARD::RubygemsHook.method(:generation_hook)) Gem.pre_uninstall(&YARD::RubygemsHook.method(:removal_hook)) yard-0.9.12/lib/yard/rubygems/backports.rb0000755000004100000410000000041513206751010020447 0ustar www-datawww-data# frozen_string_literal: true begin 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 nil # noop end yard-0.9.12/lib/yard/rubygems/doc_manager.rb0000755000004100000410000000454613206751010020727 0ustar www-datawww-data# frozen_string_literal: true begin require 'rubygems/user_interaction' require 'rubygems/doc_manager' rescue LoadError nil # noop 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 unless @spec.extra_rdoc_files.empty? args << '-' args += @spec.extra_rdoc_files end end args = args.flatten.map(&: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, 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; nil end def setup_rdoc if File.exist?(@doc_dir) && !File.writable?(@doc_dir) raise Gem::FilePermissionError, @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; nil 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; nil end end yard-0.9.12/lib/yard/rubygems/backports/0000755000004100000410000000000013206751010020117 5ustar www-datawww-datayard-0.9.12/lib/yard/rubygems/backports/LICENSE.txt0000755000004100000410000000463313206751010021753 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.9.12/lib/yard/rubygems/backports/MIT.txt0000755000004100000410000000210013206751010021305 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.9.12/lib/yard/rubygems/backports/gem.rb0000755000004100000410000000044013206751010021215 0ustar www-datawww-data# frozen_string_literal: true module 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.9.12/lib/yard/rubygems/backports/source_index.rb0000755000004100000410000002236613206751010023147 0ustar www-datawww-data# frozen_string_literal: true #-- # 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| undef_method(meth) if instance_methods(true).find {|m| m.to_s == meth } 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? || curr_ver >= prev_ver || latest[name].platform != Gem::Platform::RUBY if prev_ver.nil? || (curr_ver > prev_ver && spec.platform == Gem::Platform::RUBY) result[name].clear latest[name] = spec end if spec.platform != Gem::Platform::RUBY 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 gem_pattern.name elsif gem_pattern.name.empty? // else /^#{Regexp.escape gem_pattern.name}$/ end else requirement = platform_only || Gem::Requirement.default gem_pattern = /#{gem_pattern}/i end unless Gem::Requirement === requirement requirement = Gem::Requirement.create requirement end specs = all_gems.values.select do |spec| spec.name =~ gem_pattern && requirement.satisfied_by?(spec.version) end if only_platform specs = specs.select do |spec| Gem::Platform.match spec.platform end end specs.sort_by(&: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 && local.version < latest end outdateds end def ==(other) # :nodoc: self.class === other && @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.9.12/lib/yard/rubygems/specification.rb0000755000004100000410000000233113206751010021276 0ustar www-datawww-data# frozen_string_literal: true require '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 if class_variable_defined?(:@@default_value) if @@default_value.frozen? t = @@default_value.dup t[:has_rdoc] = true @@default_value = t.freeze else @@default_value[:has_rdoc] = true end end @@attributes << 'has_rdoc' if class_variable_defined?(:@@attributes) @@nil_attributes << 'has_rdoc' if class_variable_defined?(:@@nil_attributes) end end yard-0.9.12/lib/yard/options.rb0000755000004100000410000001762613206751010016331 0ustar www-datawww-data# frozen_string_literal: true module 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 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.empty? log.debug "Attempting to access unregistered key #{meth} on #{self.class}" instance_variable_defined?("@#{meth}") ? instance_variable_get("@#{meth}") : nil 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_defined?("@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 def tap; yield(self); self end unless defined?(tap) # only for 1.8.6 end end yard-0.9.12/lib/yard/rake/0000755000004100000410000000000013206751010015214 5ustar www-datawww-datayard-0.9.12/lib/yard/rake/yardoc_task.rb0000755000004100000410000000527213206751010020055 0ustar www-datawww-data# frozen_string_literal: true require '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 # Options to pass to {CLI::Stats} # @return [Array] the options passed to the stats utility attr_accessor :stats_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 = [] @stats_options = [] @files = [] yield self if block_given? self.options += ENV['OPTS'].split(/[ ,]/) if ENV['OPTS'] self.files += ENV['FILES'].split(/[ ,]/) if ENV['FILES'] self.options << '--no-stats' unless stats_options.empty? define end protected # Defines the rake task # @return [void] def define desc "Generate YARD Documentation" unless ::Rake.application.last_description 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)) YARD::CLI::Stats.run(*(stats_options + ['--use-cache'])) unless stats_options.empty? after.call if after.is_a?(Proc) end end end end end yard-0.9.12/lib/yard/verifier.rb0000755000004100000410000001153113206751010016436 0ustar www-datawww-data# frozen_string_literal: true module 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| next unless nil.respond_to?(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) begin; undef __execute; rescue NameError; end 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.9.12/lib/yard/gem_index.rb0000755000004100000410000000124213206751010016560 0ustar www-datawww-data# frozen_string_literal: true # Backward compatibility for gem specification lookup # @see Gem::SourceIndex module YARD module GemIndex module_function def find_all_by_name(*args) if defined?(Gem::Specification) && Gem::Specification.respond_to?(:find_all_by_name) Gem::Specification.find_all_by_name(*args) else Gem.source_index.find_name(*args) end end def each(&block) if defined?(Gem::Specification) && Gem::Specification.respond_to?(:each) Gem::Specification.each(&block) else Gem.source_index.find_name('').each(&block) end end def all each.to_a end end end yard-0.9.12/lib/yard/server/0000755000004100000410000000000013206751010015600 5ustar www-datawww-datayard-0.9.12/lib/yard/server/doc_server_helper.rb0000755000004100000410000000711413206751010021625 0ustar www-datawww-data# frozen_string_literal: true module 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) # rubocop:disable Lint/UnusedMethodArgument return '' if obj.nil? return url_for_index if obj == '_index.html' return abs_url(base_path(router.static_prefix), obj) if String === obj url = super(obj, anchor, false) return unless url abs_url(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 fname = filename.sub(%r{^#{@library.source_path.to_s}/}, '') fname += "##{anchor}" if anchor && !anchor.empty? abs_url(base_path(router.docs_prefix), 'file', fname) 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) abs_url(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 options.file ? url_for_file(options.file) : url_for(object) 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 options.readme ? url_for_file(options.readme) : url_for_index end # Returns the URL for the alphabetic index page # @return (see Templates::Helpers::HtmlHelper#url_for_index) def url_for_index abs_url(base_path(router.docs_prefix), 'index') end # @param path_components [Array] components of a URL # @return [String] the absolute path from any mounted base URI. def abs_url(*path_components) File.join(router.request.script_name, *path_components) 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 # @return [String] a timestamp for a given file def mtime(file) file = YARD::Server::Commands::StaticFileHelpers.find_file(@adapter, file) file ? File.mtime(file).to_i : nil end # @return [String] a URL for a file with a timestamp def mtime_url(file) url = url_for(file) time = mtime(file) url + (time ? "?#{time}" : "") end end end end yard-0.9.12/lib/yard/server/static_caching.rb0000755000004100000410000000337613206751010021104 0ustar www-datawww-data# frozen_string_literal: true module 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.9.12/lib/yard/server/router.rb0000755000004100000410000001536313206751010017460 0ustar www-datawww-data# frozen_string_literal: true module 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}, # {#static_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 static_prefix; 'mystatic' 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::RootRequestCommand} 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 result = check_static_cache || route result ? result : RootRequestCommand.new(adapter.options).call(request) 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 # @return [String] the URI prefix for all static assets (templates) def static_prefix; 'static' 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 = nil paths = paths.dup libs = adapter.libraries[paths.first] if libs paths.shift library = libs.find {|l| l.version == paths.first } if library 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_info) path = path.gsub(%r{//+}, '/').gsub(%r{^/|/$}, '') return route_index if path.empty? || path == docs_prefix case path when %r{^(#{docs_prefix}|#{list_prefix}|#{search_prefix}|#{static_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) when static_prefix; route_static(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 = DisplayObjectCommand 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 def route_static(library, paths) StaticFileCommand.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) path = File.cleanpath(paths.join('/')).gsub(%r{^(\.\./)+}, '') adapter.options.merge(:library => library, :path => path) end end end end yard-0.9.12/lib/yard/server/doc_server_serializer.rb0000755000004100000410000000241713206751010022520 0ustar www-datawww-data# frozen_string_literal: true 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 def initialize(_command = nil) super(:basepath => '', :extension => '') end def serialized_path(object) case object when CodeObjects::RootObject "toplevel" when CodeObjects::ExtendedMethodObject 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 Templates::Helpers::HtmlHelper.urlencode(name) end end end end yard-0.9.12/lib/yard/server/commands/0000755000004100000410000000000013206751010017401 5ustar www-datawww-datayard-0.9.12/lib/yard/server/commands/list_command.rb0000755000004100000410000000122513206751010022402 0ustar www-datawww-data# frozen_string_literal: true module 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.9.12/lib/yard/server/commands/display_object_command.rb0000755000004100000410000000325213206751010024424 0ustar www-datawww-data# frozen_string_literal: true module 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 filename = options.readme.filename opts = adapter.options.merge( :index => true, :library => library, :path => filename.sub(%r{^#{library.source_path.to_s}/}, '') ) self.status, self.headers, self.body = *DisplayFileCommand.new(opts).call(request) cache(body) return else self.path = 'index' end end return index if path == 'index' object = Registry.at(object_path) if object options.update(:type => :layout) render(object) else not_found 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.9.12/lib/yard/server/commands/root_request_command.rb0000755000004100000410000000047413206751010024167 0ustar www-datawww-data# frozen_string_literal: true module YARD module Server module Commands # Serves requests from the root of the server class RootRequestCommand < Base include StaticFileHelpers def run static_template_file? || favicon? || not_found end end end end end yard-0.9.12/lib/yard/server/commands/frames_command.rb0000755000004100000410000000060013206751010022700 0ustar www-datawww-data# frozen_string_literal: true module 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.9.12/lib/yard/server/commands/library_index_command.rb0000755000004100000410000000131613206751010024263 0ustar www-datawww-data# frozen_string_literal: true module YARD module Server module Commands class LibraryIndexOptions < CLI::YardocOptions attr_accessor :adapter, :libraries default_attr :template, :doc_server default_attr :type, :library_list default_attr :serialize, false end # Returns the index of libraries served by the server. class LibraryIndexCommand < Base attr_accessor :options def run return unless path.empty? self.options = LibraryIndexOptions.new options.adapter = adapter options.libraries = adapter.libraries options.reset_defaults render end end end end end yard-0.9.12/lib/yard/server/commands/static_file_helpers.rb0000755000004100000410000000366713206751010023755 0ustar www-datawww-data# frozen_string_literal: true require 'webrick/httputils' module YARD module Server module Commands # Include this module to get access to {#static_template_file?} # and {favicon?} helpers. module StaticFileHelpers include WEBrick::HTTPUtils # Serves an empty favicon. # @raise [FinishRequest] finalizes an empty body if the path matches # /favicon.ico so browsers don't complain. def favicon? return unless request.path == '/favicon.ico' headers['Content-Type'] = 'image/png' self.status = 200 self.body = '' raise FinishRequest end # Attempts to route a path to a static template file. # # @raise [FinishRequest] if a file was found and served # @return [void] def static_template_file? # this const was defined in StaticFileCommand originally default_mime_types = StaticFileCommand::DefaultMimeTypes file = find_file(adapter, path) if file ext = "." + (path[/\.(\w+)$/, 1] || "html") headers['Content-Type'] = mime_type(ext, default_mime_types) self.body = File.read(file) raise FinishRequest end end module_function def find_file(adapter, url) # this const was defined in StaticFileCommand originally static_paths = StaticFileCommand::STATIC_PATHS file = nil ([adapter.document_root] + static_paths.reverse).compact.each do |path_prefix| file = File.join(path_prefix, url) p file break if File.exist?(file) file = nil end # Search in default/fulldoc/html template if nothing in static asset paths assets_template = Templates::Engine.template(:default, :fulldoc, :html) file || assets_template.find_file(url) end end end end end yard-0.9.12/lib/yard/server/commands/static_file_command.rb0000755000004100000410000000127413206751010023721 0ustar www-datawww-data# frozen_string_literal: true module YARD module Server module Commands # Serves static content when no other router matches a request class StaticFileCommand < LibraryCommand include StaticFileHelpers 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 static_template_file? || not_found end end end end end yard-0.9.12/lib/yard/server/commands/display_file_command.rb0000755000004100000410000000172213206751010024075 0ustar www-datawww-data# frozen_string_literal: true module YARD module Server module Commands # Displays a README or extra file. # # @todo Implement better support for detecting binary (image) filetypes class DisplayFileCommand < LibraryCommand attr_accessor :index def run filename = File.cleanpath(File.join(library.source_path, path)) raise NotFoundError unless File.file?(filename) if filename =~ /\.(jpe?g|gif|png|bmp)$/i headers['Content-Type'] = StaticFileCommand::DefaultMimeTypes[$1.downcase] || 'text/html' render File.read_binary(filename) else file = CodeObjects::ExtraFileObject.new(filename) options.update :object => Registry.root, :type => :layout, :file => file, :index => index ? true : false render end end end end end end yard-0.9.12/lib/yard/server/commands/base.rb0000755000004100000410000001620513206751010020647 0ustar www-datawww-data# frozen_string_literal: true require '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_info[1..-1] self.headers = {'Content-Type' => 'text/html'} self.body = '' self.status = 200 add_cache_control begin run rescue FinishRequest nil # noop rescue NotFoundError => e self.body = e.message if e.message != e.class.to_s not_found end # keep this to support commands setting status manually. 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_info.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 for a 404 response. Does not modify the # body if already set. # # @return [void] def not_found self.status = 404 return unless body.empty? self.body = "Not found: #{request.path}" headers['Content-Type'] = 'text/plain' headers['X-Cascade'] = 'pass' headers.delete('Cache-Control') 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 private # Add a conservative cache control policy to reduce load on # requests served with "?1234567890" style timestamp query strings. def add_cache_control return if request.query_string.to_i == 0 headers['Cache-Control'] = 'private, max-age=300' end end end end end yard-0.9.12/lib/yard/server/commands/library_command.rb0000755000004100000410000001336113206751010023077 0ustar www-datawww-data# frozen_string_literal: true require '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 begin Process.fork { exit 0 } CAN_FORK = true rescue Exception # rubocop:disable Lint/RescueException CAN_FORK = false end # @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 # @return [Boolean] whether or not this adapter calls +fork+ when serving # library requests. Defaults to false. attr_accessor :use_fork # 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) if can_fork? call_with_fork(request) { super } else begin save_default_template_info call_without_fork(request) { super } ensure restore_template_info end end end private def call_without_fork(request) self.request = request self.options = LibraryOptions.new options.reset_defaults options.command = self setup_library options.title = "Documentation for #{library.name} " + (library.version ? '(' + library.version + ')' : '') yield rescue LibraryNotPreparedError not_prepared end def call_with_fork(request, &block) reader, writer = IO.pipe fork do log.debug "[pid=#{Process.pid}] fork serving: #{request.path}" reader.close writer.print(Marshal.dump(call_without_fork(request, &block))) end writer.close Marshal.load(reader.read) end def can_fork? CAN_FORK && use_fork end 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.ready? 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 options.update(:template => :doc_server, :type => :processing) self.caching = false self.status = 202 self.body = render self.headers = {'Content-Type' => 'text/html'} [status, headers, [body]] 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; define_method(:init) {} end obj.class = tplclass obj.send(:initialize, options) class << obj attr_reader :contents define_method(:asset) {|_, contents| @contents = contents } end obj end end end end end yard-0.9.12/lib/yard/server/commands/search_command.rb0000755000004100000410000000457413206751010022706 0ustar www-datawww-data# frozen_string_literal: true module 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(abs_url(adapter.router.docs_prefix, single_library ? library : '')) if query.nil? || query =~ /\A\s*\Z/ found = Registry.at(query) redirect(url_for(found)) if found search_for_object request.xhr? ? serve_xhr : serve_normal end def visible_results results[0, 10] end private def url_for(object) abs_url(base_path(router.docs_prefix), serializer.serialized_path(object)) end def serve_xhr 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 # rubocop:disable Style/MultilineBlockChain self.results = run_verifier(Registry.all).select do |o| o.path.downcase.include?(query.downcase) end.reject do |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 end.sort_by do |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 end yard-0.9.12/lib/yard/server/templates/0000755000004100000410000000000013206751010017576 5ustar www-datawww-datayard-0.9.12/lib/yard/server/templates/default/0000755000004100000410000000000013206751010021222 5ustar www-datawww-datayard-0.9.12/lib/yard/server/templates/default/method_details/0000755000004100000410000000000013206751010024207 5ustar www-datawww-datayard-0.9.12/lib/yard/server/templates/default/method_details/html/0000755000004100000410000000000013206751010025153 5ustar www-datawww-datayard-0.9.12/lib/yard/server/templates/default/method_details/html/permalink.erb0000755000004100000410000000034513206751010027634 0ustar www-datawww-data yard-0.9.12/lib/yard/server/templates/default/method_details/html/setup.rb0000755000004100000410000000015513206751010026644 0ustar www-datawww-data# frozen_string_literal: true def init super sections.place(:permalink).after_any(:method_signature) end yard-0.9.12/lib/yard/server/templates/default/layout/0000755000004100000410000000000013206751010022537 5ustar www-datawww-datayard-0.9.12/lib/yard/server/templates/default/layout/html/0000755000004100000410000000000013206751010023503 5ustar www-datawww-datayard-0.9.12/lib/yard/server/templates/default/layout/html/script_setup.erb0000755000004100000410000000047513206751010026732 0ustar www-datawww-data yard-0.9.12/lib/yard/server/templates/default/layout/html/setup.rb0000755000004100000410000000020513206751010025170 0ustar www-datawww-data# frozen_string_literal: true def javascripts super + %w(js/autocomplete.js) end def stylesheets super + %w(css/custom.css) end yard-0.9.12/lib/yard/server/templates/default/layout/html/breadcrumb.erb0000755000004100000410000000341313206751010026307 0ustar www-datawww-data yard-0.9.12/lib/yard/server/templates/default/fulldoc/0000755000004100000410000000000013206751010022652 5ustar www-datawww-datayard-0.9.12/lib/yard/server/templates/default/fulldoc/html/0000755000004100000410000000000013206751010023616 5ustar www-datawww-datayard-0.9.12/lib/yard/server/templates/default/fulldoc/html/js/0000755000004100000410000000000013206751010024232 5ustar www-datawww-datayard-0.9.12/lib/yard/server/templates/default/fulldoc/html/js/autocomplete.js0000755000004100000410000001750313206751010027302 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.9.12/lib/yard/server/templates/default/fulldoc/html/images/0000755000004100000410000000000013206751010025063 5ustar www-datawww-datayard-0.9.12/lib/yard/server/templates/default/fulldoc/html/images/processing.gif0000755000004100000410000000234313206751010027733 0ustar www-datawww-dataGIF89aõøøøèèèÒÒÒ¼¼¼®®®¢¢¢ÜÜܸ¸¸šššäääØØØªªª   °°°ÌÌÌööö¨¨¨ÔÔÔÿÿÿ666&&&PPPÄÄÄppp’’’VVVúúúhhhFFFÆÆÆHHH222æææ!ÿ NETSCAPE2.0!ù ÿ,ÿ@‰pH „‚dR¹ Ĩth8 ®W e»Ý4Sib€-k¹ÜK'²…£\ Øí¡ån¯1|!!B‹ C|Gvs  A!ù !,W@‰p(| ŽÇ‘˜@ ˡÉD… ªà¡"Q„zˆv$^QSàPÐH«$`Ád(ø÷q‘æÿx C€K†x ‰†gŽy WWCA!ù , M "Jdž¨”Hb+Q\¡¥g!ìHíT†YÉ#áh´p8žr—;º>KeÓ‰`,I¢ˆ‘$H¤ÖñŒ ˆlÑx lvœ}1Èè—b׃6"h8¤ƒ’€`@(„!ù !, YÀpñC…r\–Kc n¨NÇ¥BlFzR1 Ö"œ`Ǹ°€¨×B‚½žöB€ !€B€ !ŠBvG ur GA!ù !,V@‰pHt .• qhl(PèRÒ¹D¯Ë…çŠ%~¸]‰‚!G…‰QŽf0–€p°^—9 ÑP¯S§} S‚S‚ ‹t}‚ ‚A;yard-0.9.12/lib/yard/server/templates/default/fulldoc/html/css/0000755000004100000410000000000013206751010024406 5ustar www-datawww-datayard-0.9.12/lib/yard/server/templates/default/fulldoc/html/css/custom.css0000755000004100000410000000575013206751010026444 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; } form.search { z-index: 8000; position: absolute; color: #fff; border: 1px solid #99f; width: 210px; background: #05a; border-radius: 4px; border-top-left-radius: 0; border-top-right-radius: 0; } form.search input { height: 25px; padding: 0; padding-left: 4px; margin: 4px; margin-right: 0; width: 202px; border: 1px solid #99f; border-radius: 3px; font-size: 1.1em; box-sizing: border-box; -webkit-appearance: none; } @media (max-width: 920px) { form.search { position: absolute; color: #fff; width: 100%; margin-top: 0; background: #05a; border-radius: 0; border: 0; margin-bottom: 10px; left: 0; top: 0; } form.search input { margin-top: 9px; margin-bottom: 11px; margin-left: 12px; padding-left: 6px; border: 1px solid #eaf0ff; } #menu { margin-top: 41px; } #search a { border-top-left-radius: 3px; border-top-right-radius: 3px; background: none; border: 0; box-shadow: none; margin-top: 4px; padding-bottom: 5px; color: #eaf0ff; fill: #eaf0ff; } #search a.active { background: #048; border: 0; } } @media (min-width: 920px) { form.search { right: 12px; top: 0; } } #menu { padding-top: 5px; } #content h1 { margin-top: 15px; 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.9.12/lib/yard/server/templates/doc_server/0000755000004100000410000000000013206751010021731 5ustar www-datawww-datayard-0.9.12/lib/yard/server/templates/doc_server/library_list/0000755000004100000410000000000013206751010024430 5ustar www-datawww-datayard-0.9.12/lib/yard/server/templates/doc_server/library_list/html/0000755000004100000410000000000013206751010025374 5ustar www-datawww-datayard-0.9.12/lib/yard/server/templates/doc_server/library_list/html/headers.erb0000755000004100000410000000114013206751010027500 0ustar www-datawww-data YARD Documentation Server <%= YARD::VERSION %> - Library Listing yard-0.9.12/lib/yard/server/templates/doc_server/library_list/html/title.erb0000755000004100000410000000012113206751010027204 0ustar www-datawww-data

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

            Library Listing

            yard-0.9.12/lib/yard/server/templates/doc_server/library_list/html/setup.rb0000755000004100000410000000020313206751010027057 0ustar www-datawww-data# frozen_string_literal: true include T('default/layout/html') def init sections :library_list, [:title, :listing, :footer] end yard-0.9.12/lib/yard/server/templates/doc_server/library_list/html/listing.erb0000755000004100000410000000117413206751010027545 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.9.12/lib/yard/server/templates/doc_server/library_list/html/library_list.erb0000755000004100000410000000054413206751010030573 0ustar www-datawww-data <%= erb(:headers) %>
            <%= yieldall %>
            yard-0.9.12/lib/yard/server/templates/doc_server/search/0000755000004100000410000000000013206751010023176 5ustar www-datawww-datayard-0.9.12/lib/yard/server/templates/doc_server/search/html/0000755000004100000410000000000013206751010024142 5ustar www-datawww-datayard-0.9.12/lib/yard/server/templates/doc_server/search/html/search.erb0000755000004100000410000000130313206751010026101 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.9.12/lib/yard/server/templates/doc_server/search/html/setup.rb0000755000004100000410000000030613206751010025631 0ustar www-datawww-data# frozen_string_literal: true def init sections :search, [T('../default/layout')] end def search options.breadcrumb_title = h("Search for '#{@query}'") yieldall :contents => erb(:search) end yard-0.9.12/lib/yard/server/templates/doc_server/processing/0000755000004100000410000000000013206751010024105 5ustar www-datawww-datayard-0.9.12/lib/yard/server/templates/doc_server/processing/html/0000755000004100000410000000000013206751010025051 5ustar www-datawww-datayard-0.9.12/lib/yard/server/templates/doc_server/processing/html/processing.erb0000755000004100000410000000471113206751010027725 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.9.12/lib/yard/server/templates/doc_server/processing/html/setup.rb0000755000004100000410000000010213206751010026532 0ustar www-datawww-data# frozen_string_literal: true def init sections :processing end yard-0.9.12/lib/yard/server/webrick_adapter.rb0000755000004100000410000000253313206751010021261 0ustar www-datawww-data# frozen_string_literal: true require '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 # @private def do_GET(request, response) # rubocop:disable Style/MethodName 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'] || "").casecmp('xmlhttprequest') == 0 end end yard-0.9.12/lib/yard/server/library_version.rb0000755000004100000410000002626713206751010021356 0ustar www-datawww-data# frozen_string_literal: true require 'fileutils' require 'thread' 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, 3 methods can be added to the +LibraryVersion+ # class, +#load_yardoc_from_SOURCE+, +#yardoc_file_for_SOURCE+, and # +#source_path_for_SOURCE+. In all cases, "SOURCE" represents the source # type used in {#source} when creating the library object. The # +#yardoc_file_for_SOURCE+ and +#source_path_for_SOURCE+ methods are 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. # # Note that only +#load_yardoc_from_SOURCE+ is required. The other two # methods are optional and can be set manually (via {#source_path=} and # {#yardoc_file=}) on the object at any time. # # @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 # 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}") # end # # # tell the server it's not ready yet (but it might be next time) # raise LibraryNotPreparedError # end # # def yardoc_file_for_http # "/path/to/yardocs/#{self}/.yardoc" # end # # def source_path_for_http # File.dirname(yardoc_file) # 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. # @note To implement a custom yardoc file getter, implement def yardoc_file @yardoc_file ||= load_yardoc_file end attr_writer :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" def source_path @source_path ||= load_source_path end attr_writer :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 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.to_s 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? # @return [Boolean] whether the library has been completely processed # and is ready to be served def ready? return false if yardoc_file.nil? serializer.complete? end # @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 ready? 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" YARD::GemIndex.find_all_by_name(name, ver).last end protected @@chdir_mutex = Mutex.new # Called when a library of source type "disk" is to be prepared. In this # case, the {#yardoc_file} should already be set, but the library may not # be prepared. Run preparation if not done. # # @raise [LibraryNotPreparedError] if the yardoc file has not been # prepared. def load_yardoc_from_disk return if ready? @@chdir_mutex.synchronize do Dir.chdir(source_path_for_disk) do Thread.new do CLI::Yardoc.run('--no-stats', '-n', '-b', yardoc_file) end end end raise LibraryNotPreparedError 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 return if ready? ver = version ? "= #{version}" : ">= 0" @@chdir_mutex.synchronize do Thread.new do # Build gem docs on demand log.debug "Building gem docs for #{to_s(false)}" CLI::Gems.run(name, ver) log.debug "Done building gem docs for #{to_s(false)}" end end raise LibraryNotPreparedError 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 # @return [String] the yardoc file for a gem source def yardoc_file_for_gem require 'rubygems' ver = version ? "= #{version}" : ">= 0" Registry.yardoc_file_for_gem(name, ver) end private def load_source_path meth = "source_path_for_#{source}" send(meth) if respond_to?(meth, true) end def load_yardoc_file meth = "yardoc_file_for_#{source}" send(meth) if respond_to?(meth, true) end def serializer return if yardoc_file.nil? Serializers::YardocSerializer.new(yardoc_file) end end end end yard-0.9.12/lib/yard/server/rack_adapter.rb0000755000004100000410000000640013206751010020550 0ustar www-datawww-data# frozen_string_literal: true require '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'] || "").casecmp("xmlhttprequest") == 0 end end yard-0.9.12/lib/yard/server/adapter.rb0000755000004100000410000001033413206751010017551 0ustar www-datawww-data# frozen_string_literal: true module 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.9.12/lib/yard/parser/0000755000004100000410000000000013206751010015566 5ustar www-datawww-datayard-0.9.12/lib/yard/parser/c/0000755000004100000410000000000013206751010016010 5ustar www-datawww-datayard-0.9.12/lib/yard/parser/c/c_parser.rb0000755000004100000410000001525213206751010020143 0ustar www-datawww-data# frozen_string_literal: true module 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 when '}'; advance # Skip possible C++ namespace closing brackets. 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/ # Skip C++ namespace - treat content as top level statement. return nil if decl =~ /\A(namespace)/ 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 # rubocop:disable Lint/UselessSetterCall end def consume_body_statements stmts = [] brace_level = 1 loop do strip_non_statement_data start = @index line = @line consume_until(/[{};]/) brace_level += 1 if prevchar == '{' brace_level -= 1 if prevchar == '}' break if prevchar.empty? || (brace_level <= 0 && prevchar == '}') src = @content[start...@index] next unless src && src !~ /\A\s*\Z|\A\}\Z/ stmt = BodyStatement.new(src, @file, line) attach_comment(stmt) stmts << stmt end stmts end def strip_non_statement_data start = @index loop do start = @index case char when /\s/; consume_whitespace when '#'; consume_directive when '/'; consume_comment end break if start == @index end 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 = String.new("") 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 break if chr == '{' || chr == '(' break if bracket_level <= 0 && brace_level <= 0 end end @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 yield while @index <= @content.size 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[a-zA-Z0-9]+\s\{/ end end end end end yard-0.9.12/lib/yard/parser/c/statement.rb0000755000004100000410000000251313206751010020345 0ustar www-datawww-data# frozen_string_literal: true module 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.9.12/lib/yard/parser/c/comment_parser.rb0000755000004100000410000001117113206751010021357 0ustar www-datawww-data# frozen_string_literal: true module 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|attr|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 = $1 blkparams = $2 else blk = nil blkparams = 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", "ary", "new_ary", /^\[/; "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(%r{/?\*--\n(.*?)/?\*\+\+}m, '') comment = comment.sub(%r{/?\*--\n.*}m, '') comment end end end end end yard-0.9.12/lib/yard/parser/source_parser.rb0000755000004100000410000004663713206751010021012 0ustar www-datawww-data# frozen_string_literal: true require '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 < RuntimeError; 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 until files.empty? 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 = %r{\A(?:\s*#*!.*\r?\n)?\s*(?:#+|/\*+|//+).*coding\s*[:=]{1,2}\s*([a-z\d_\-]+)}i FROZEN_STRING_LINE = /frozen(-|_)string(-|_)literal: true/i # The default glob of files to be parsed. # @since 0.9.0 DEFAULT_PATH_GLOB = ["{lib,app}/**/*.rb", "ext/**/*.{c,cc,cxx,cpp}"] # Byte order marks for various encodings # @since 0.7.0 ENCODING_BYTE_ORDER_MARKS = { 'utf-8' => String.new("\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 = DEFAULT_PATH_GLOB, 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,cc,cxx,cpp}" : p }. map {|p| p.include?("*") ? Dir[p].sort_by {|d| [d.length, d] } : 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 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 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 return if before_parse_list_callbacks.any? do |cb| 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(String.new(File.read_binary(file))) checksum = Registry.checksum_for(content) return if Registry.checksums[file] == checksum if Registry.checksums.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) enumerator = @parser.enumerator if enumerator post = Handlers::Processor.new(self) post.process(enumerator) end 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] unless klass raise ArgumentError, "invalid parser type '#{parser_type}' or unrecognized file", caller[1..-1] end klass end end end end yard-0.9.12/lib/yard/parser/base.rb0000755000004100000410000000370313206751010017033 0ustar www-datawww-data# frozen_string_literal: true module 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) # rubocop:disable Lint/UnusedMethodArgument 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 end yard-0.9.12/lib/yard/parser/ruby/0000755000004100000410000000000013206751010016547 5ustar www-datawww-datayard-0.9.12/lib/yard/parser/ruby/ruby_parser.rb0000755000004100000410000005526713206751010021453 0ustar www-datawww-data# frozen_string_literal: true begin require 'ripper'; rescue LoadError; nil end module YARD module Parser module Ruby # Ruby 1.9 parser # @!attribute [r] encoding_line # @!attribute [r] frozen_string_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 def frozen_string_line; @parser.frozen_string_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, :frozen_string_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 @frozen_string_line = nil @file_encoding = nil @newline = true @percent_ary = 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 match = @encoding_line.match(SourceParser::ENCODING_LINE) @file_encoding = match.captures.last if match 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, :words_literal => :words_beg, :qsymbols_literal => :qsymbols_beg, :symbols_literal => :symbols_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 {|vv| (REV_MAPPINGS[vv] ||= []) << 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 && 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.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 = pair.first 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) || (!@newline && %w(if while until unless).include?(tok)) (@map[tok] ||= []) << [lineno, charno] end visit_ns_token(:#{event}, tok, true) end eof end [: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) @newline = true @charno += tok ? tok.length : 0 end eof end undef on_sp def on_sp(tok) add_token(:sp, tok) @charno += tok.length 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 = node.block.source_range lr = node.block.line_range node.block.source_range = Range.new(sr.first, @tokens.last[2][1] - 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 @newline = [:semicolon, :comment, :kw, :op, :lparen, :lbrace].include?(token) if ast_token AstNode.new(token, [data], :line => lineno..lineno, :char => ch..charno - 1, :token => true) end end def add_token(token, data) if @percent_ary if token == :words_sep && data !~ /\s\z/ rng = @percent_ary.source_range rng = Range.new(rng.first, rng.last + data.length) @percent_ary.source_range = rng @tokens << [token, data, [lineno, charno]] @percent_ary = nil return elsif token == :tstring_end && data =~ /\A\s/ rng = @percent_ary.source_range rng = Range.new(rng.first, rng.last + data.length) @percent_ary.source_range = rng @tokens << [token, data, [lineno, charno]] @percent_ary = nil return end end 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_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, :until_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 %w(symbols qsymbols words qwords).each do |kw| module_eval(<<-eof, __FILE__, __LINE__ + 1) begin; undef on_#{kw}_new; rescue NameError; end def on_#{kw}_new(*args) node = LiteralNode.new(:#{kw}_literal, args) @percent_ary = node if @map[:#{kw}_beg] lstart, sstart = *@map[:#{kw}_beg].pop node.source_range = Range.new(sstart, @ns_charno-1) node.line_range = Range.new(lstart, lineno) end node end begin; undef on_#{kw}_add; rescue NameError; end def on_#{kw}_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 eof 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| next arg unless arg.class == Array if arg.first.class == Array arg.map! do |sub_arg| next sub_arg unless sub_arg.class == Array type = sub_arg[0].type == :label ? :named_arg : :unnamed_optional_arg AstNode.new(type, sub_arg, :listline => lineno..lineno, :listchar => charno..charno) end end AstNode.new(:list, arg, :listline => lineno..lineno, :listchar => charno..charno) 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.empty? if comment =~ SourceParser::SHEBANG_LINE && !@encoding_line @shebang_line = comment not_comment = true elsif comment =~ SourceParser::ENCODING_LINE @encoding_line = comment not_comment = true elsif comment =~ SourceParser::FROZEN_STRING_LINE @frozen_string_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 && comment_starts_line?(ch) @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 unless append_comment @comments_last_column = column end def on_embdoc_beg(text) visit_ns_token(:embdoc_beg, text) @embdoc_start = charno - text.length @embdoc = String.new("") 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 alias compile_error on_parse_error def comment_starts_line?(charno) (charno - 1).downto(0) do |i| ch = @source[i] break if ch == "\n" return false if ch != " " && ch != "\t" end true end def insert_comments root.traverse do |node| next if node.type == :comment || node.type == :list || node.parent.type != :list # never attach comments to if/unless mod nodes if node.type == :if_mod || node.type == :unless_mod node = node.then_block end # 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| add_comment(line, nil, node) if node.line > line 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| next unless 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 unless @comments.empty? # 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) nodes = [node || root] until nodes.empty? p_node = nodes.shift p_node.children.each do |child| child.parent = p_node nodes << child end end end end if defined?(::Ripper) end end end yard-0.9.12/lib/yard/parser/ruby/token_resolver.rb0000755000004100000410000001154013206751010022141 0ustar www-datawww-data# frozen_string_literal: true module YARD module Parser module Ruby # Supports {#each} enumeration over a source's tokens, yielding # the token and a possible {CodeObjects::Base} associated with the # constant or identifier token. class TokenResolver include Enumerable # Creates a token resolver for given source. # # @param source [String] the source code to tokenize # @param namespace [CodeObjects::Base] the object/namespace to resolve from def initialize(source, namespace = Registry.root) @tokens = RubyParser.parse(source, '(tokenize)').tokens raise ParserSyntaxError if @tokens.empty? && !source.empty? @default_namespace = namespace end # Iterates over each token, yielding the token and a possible code # object that is associated with the token. # # @yieldparam token [Array(Symbol,String,Array(Integer,Integer))] the # current token object being iterated # @yieldparam object [CodeObjects::Base, nil] the fully qualified code # object associated with the current token, or nil if there is no object # for the yielded token. # @example Yielding code objects # r = TokenResolver.new("A::B::C") # r.each do |tok, obj| # if obj # puts "#{tok[0]} -> #{obj.path.inspect}" # else # puts "No object: #{tok.inspect}" # end # end # # # Prints: # # :const -> "A" # # No object: [:op, "::"] # # :const -> "A::B" # # No object: [:op, "::"] # # :const -> "A::B::C" def each @states = [] push_state @tokens.each do |token| yield_obj = false if skip_group && [:const, :ident, :op, :period].include?(token[0]) yield token, nil next else self.skip_group = false end case token[0] when :const lookup(token[0], token[1]) yield_obj = true self.last_sep = nil when :ident lookup(token[0], token[1]) yield_obj = true self.last_sep = nil when :op, :period self.last_sep = token[1] unless CodeObjects.types_for_separator(token[1]) self.object = nil self.last_sep = nil end when :lparen push_state when :rparen pop_state else self.object = nil end yield token, (yield_obj ? object : nil) if next_object self.object = next_object self.next_object = nil end self.skip_group = true if yield_obj && object.nil? end end def self.state_attr(*attrs) attrs.each do |attr| define_method(attr) { @states.last[attr.to_sym] } define_method("#{attr}=") {|v| @states.last[attr.to_sym] = v } protected attr, :"#{attr}=" end end private def push_state @states.push :object => nil, :skip_group => false, :last_sep => nil end def pop_state @states.pop end state_attr :object, :next_object, :skip_group, :last_sep def lookup(toktype, name) types = object_resolved_types return self.object = nil if types.empty? if toktype == :const types.any? do |type| prefix = (type ? type.path : "") + last_sep.to_s self.object = Registry.resolve(@default_namespace, "#{prefix}#{name}", true) end else # ident types.any? do |type| obj = Registry.resolve(type, name, true) if obj.nil? && name == "new" obj = Registry.resolve(object, "#initialize", true) self.next_object = object if obj.nil? end self.object = obj end end end def object_resolved_types(obj = object) return [obj] unless obj.is_a?(CodeObjects::MethodObject) resolved_types = [] tags = obj.tags(:return) tags += obj.tags(:overload).map {|o| o.tags(:return) }.flatten tags.each do |tag| next if tag.types.nil? tag.types.each do |type| type = type.sub(/<.+>/, '') if type == "self" resolved_types << obj.parent else type_obj = Registry.resolve(obj, type, true) resolved_types << type_obj if type_obj end end end resolved_types end end end end end yard-0.9.12/lib/yard/parser/ruby/legacy/0000755000004100000410000000000013206751010020013 5ustar www-datawww-datayard-0.9.12/lib/yard/parser/ruby/legacy/ruby_parser.rb0000755000004100000410000000123413206751010022700 0ustar www-datawww-data# frozen_string_literal: true module 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 end yard-0.9.12/lib/yard/parser/ruby/legacy/statement_list.rb0000755000004100000410000003173613206751010023414 0ustar www-datawww-data# frozen_string_literal: true module 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 @comments_last_line = nil if content.is_a? TokenList @tokens = content.dup elsif content.is_a? String @tokens = TokenList.new(content.delete("\r")) else raise ArgumentError, "Invalid content for StatementList: #{content.inspect}:#{content.class}" end parse_statements end private def parse_statements loop do stmt = next_statement break if stmt.nil? 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 = TokenList.new @block = nil @comments = nil @last_tk = nil @last_ns_tk = nil @before_last_tk = nil @before_last_ns_tk = nil @first_line = nil until @done tk = @tokens.shift break if tk.nil? 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) end end def sanitize_statement_end extra = [] (@statement.size - 1).downto(0) do |index| token = @statement[index] next unless 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) break 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] break 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.start_with?('=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 if @block.nil? @block = TokenList.new tokens = [tk, TkStatementEnd.new(tk.line_no, tk.char_no)] tokens = tokens.reverse if TkBEGIN === tk.class @statement.concat(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 @tokens[1] end end end end yard-0.9.12/lib/yard/parser/ruby/legacy/token_list.rb0000755000004100000410000000377213206751010022527 0ustar www-datawww-data# frozen_string_literal: true module 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 acc << (!show_block && TkBlockContents === token ? "" : token.text) 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 << 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) loop do tk = lex.token break if tk.nil? 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 if next_tk 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 else tk end end end end end yard-0.9.12/lib/yard/parser/ruby/legacy/statement.rb0000755000004100000410000000304413206751010022350 0ustar www-datawww-data# frozen_string_literal: true module 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 end yard-0.9.12/lib/yard/parser/ruby/legacy/ruby_lex.rb0000755000004100000410000010627213206751010022204 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.is_a?(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) # rubocop:disable Style/MethodName tk = nil case token when String, Symbol source = token.is_a?(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, ":"], #: [:TkSTAR], # *arg [:TkAMPER], # &arg # [: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, ";"], [: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 self.def_token(token_n, super_token = Token, reading = nil, *opts) token_n = token_n.id2name unless token_n.is_a?(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 self.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 @colonblock_seen = false 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) || return l = "" begin l.concat c unless c == "\r" break if c == "\n" end while c = getc # rubocop:disable Lint/Loop 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).is_a?(TkNL) || tk.is_a?(TkEND_OF_SCRIPT)) && !@continue || tk.nil? end line = get_read if line == "" && tk.is_a?(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.is_a?(TkSPACE) rescue SyntaxError abort if @exception_on_syntax_error tk = TkError.new(line_no, char_no) end end while @skip_space && tk.is_a?(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 = String.new(op) @ltype = "=" begin line = String.new 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 = String.new(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 && peek(0) =~ /[0-9]/ throw :RET, identify_number(op) else @lex_state = EXPR_BEG end elsif @lex_state != EXPR_END && 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 || @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 && @space_seen && 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 && @space_seen && 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 = String.new("$") tk = case ch = getc when %r{[~_*$?!@/\\;,=:<>".]} 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 == "!" || 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 = String.new while ch = getc reserve << ch if ch == "\\" #" ch = getc reserve << ch elsif ch == "\n" break end end str = String.new 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 == "+" || start == "-" || 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 = String.new 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 != "]" && 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 = String.new nest = 0 while (ch = getc) res << ch if ch == '}' break if nest == 0 nest -= 1 elsif ch == '{' nest += 1 end end res end def identify_comment @ltype = "#" comment = String.new("#") 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 Token(TkCOMMENT).set_text(comment) end def read_escape res = String.new 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" && (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.9.12/lib/yard/parser/ruby/ast_node.rb0000755000004100000410000004027313206751010020701 0ustar www-datawww-data# frozen_string_literal: true module 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.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] @docstring = nil end # @return [Boolean] whether the node is equal to another by checking # the list and type # @private def ==(other) super && type == other.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 = dup + [:__last__] objs.unshift(type) if type && type != :list options = [] options << ['docstring', docstring] if @docstring if @source_range || @line_range options << ['line', line_range] options << ['source', source_range] end objs.pop if options.empty? 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.empty? f = children.first l = 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 unnamed_required_params self[0] end def unnamed_optional_params return @unnamed_optional_params if defined?(@unnamed_optional_params) params = self[1] || [] if self[-3] && self[-3][0] && self[-3][0].type == :unnamed_optional_arg params += self[-3] end @unnamed_optional_params = params.empty? ? nil : params end def named_params return @named_params if defined?(@named_params) if YARD.ruby2? && self[-3] && self[-3][0] && self[-3][0].type == :named_arg @named_params = self[-3] else @named_params = nil end end def splat_param self[2] ? self[2][0] : nil end def unnamed_end_params self[3] end def double_splat_param return nil unless YARD.ruby2? if (node = self[-2]).is_a?(AstNode) if node.type == :ident node elsif node.type == :kwrest_param # See https://bugs.ruby-lang.org/issues/12387 node.last end end end def block_param self[-1] ? self[-1][0] : 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] if name == :call nil elsif name_only && Array === name name.jump(:ident).first.to_sym else name end 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 return unless self[2] && !cmod? self[2].type == :elsif ? self[2] : self[2][0] 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 end yard-0.9.12/lib/yard/i18n/0000755000004100000410000000000013206751010015051 5ustar www-datawww-datayard-0.9.12/lib/yard/i18n/text.rb0000755000004100000410000001246413206751010016374 0ustar www-datawww-data# frozen_string_literal: true module 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 # receives 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 # receives 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| 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 = String.new("") 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 = String.new("") 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 = String.new("") 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.9.12/lib/yard/i18n/message.rb0000755000004100000410000000326013206751010017026 0ustar www-datawww-data# frozen_string_literal: true require "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) && @id == other.id && @locations == other.locations && @comments == other.comments end end end end yard-0.9.12/lib/yard/i18n/pot_generator.rb0000755000004100000410000002305713206751010020260 0ustar www-datawww-data# frozen_string_literal: true require "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 translate "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 # translator-comment line that is started with "# ". # # @return [String] POT format string def generate pot = String.new(header) sorted_messages = @messages.sort_by do |message| sorted_locations = message.locations.sort 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: #{generate_pot_creation_date_value}\\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 current_time @current_time ||= Time.now end def generate_pot_creation_date_value current_time.strftime("%Y-%m-%d %H:%M%z") 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.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) extract_documents(tag) if Tags::OverloadTag === tag end def extract_tag_name(tag) return if tag.name.nil? return if tag.name.is_a?(String) && 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 = String.new("@#{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 = String.new("@#{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.9.12/lib/yard/i18n/messages.rb0000755000004100000410000000304713206751010017214 0ustar www-datawww-data# frozen_string_literal: true module 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) && @messages == other.messages end protected # @return [Hash{String=>Message}] the set of message objects attr_reader :messages end end end yard-0.9.12/lib/yard/i18n/locale.rb0000755000004100000410000000346013206751010016643 0ustar www-datawww-data# frozen_string_literal: true module 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.9.12/lib/yard/i18n/po_parser.rb0000755000004100000410000000321213206751010017371 0ustar www-datawww-data# frozen_string_literal: true module 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:\n" \ "\tgem 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:\n" \ "\tgem 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.9.12/lib/yard/logging.rb0000755000004100000410000001416313206751010016255 0ustar www-datawww-data# encoding: utf-8 # frozen_string_literal: true require '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 = %w(⣷ ⣯ ⣟ ⡿ ⢿ ⣻ ⣽ ⣾) # @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 unless level > INFO # 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) self.warned = false @progress_indicator = 0 @mutex = Mutex.new @progress_msg = nil @progress_last_update = Time.now 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 # Remembers when a warning occurs and writes a warning message. def warn(*args) self.warned = true super end attr_accessor :warned # 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) 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 @mutex.synchronize do print("\e[2K\e[?25l\e[1m#{icon}#{msg}\e[0m\r") @progress_msg = msg if Time.now - @progress_last_update > 0.2 @progress_indicator += 1 @progress_indicator %= PROGRESS_INDICATORS.size @progress_last_update = Time.now end end Thread.new do sleep(0.05) progress(msg + ".", nil) if @progress_msg == msg 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 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 << 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) old_level = level self.level = new_level yield ensure 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.9.12/lib/yard/version.rb0000755000004100000410000000010313206751010016301 0ustar www-datawww-data# frozen_string_literal: true module YARD VERSION = '0.9.12' end yard-0.9.12/lib/yard/serializers/0000755000004100000410000000000013206751010016626 5ustar www-datawww-datayard-0.9.12/lib/yard/serializers/process_serializer.rb0000755000004100000410000000132113206751010023062 0ustar www-datawww-data# frozen_string_literal: true module 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.9.12/lib/yard/serializers/yardoc_serializer.rb0000755000004100000410000001047713206751010022701 0ustar www-datawww-data# frozen_string_literal: true module 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, FILELEN] == __FILE__ } raise end FILELEN = __FILE__.size 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 complete_lock_path; File.join(basepath, 'complete') end def processing_path; File.join(basepath, 'processing') end def complete? File.exist?(complete_lock_path) && !locked_for_writing? end # Creates a pessmistic transactional lock on the database for writing. # Use with {YARD.parse} to ensure the database is not written multiple # times. # # @see #locked_for_writing? def lock_for_writing File.open!(processing_path, 'w') {} yield ensure File.unlink(processing_path) if File.exist?(processing_path) end # @return [Boolean] whether the database is currently locked for writing def locked_for_writing? File.exist?(processing_path) 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.empty? 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 end yard-0.9.12/lib/yard/serializers/file_system_serializer.rb0000755000004100000410000001077613206751010023745 0ustar www-datawww-data# frozen_string_literal: true module 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 @name_map = nil @basepath = (options[:basepath] || 'doc').to_s @extension = (options.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 ? mapped_name(object) : "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 # Builds a filename mapping from object paths to filesystem path names. # Needed to handle case sensitive YARD objects mapped into a case # insensitive filesystem. Uses with {#mapped_name} to determine the # mapping name for a given object. # # @note In order to use filesystem name mapping, you must initialize # the serializer object after preparing the {YARD::Registry}. def build_filename_map @name_map = {} YARD::Registry.all.each do |object| lpath = nil if object.parent && object.parent.type != :root lpath = object.parent.path + "::" + object.name.to_s.downcase else lpath = object.path.downcase end @name_map[lpath] ||= {} size = @name_map[lpath].size name = "#{object.name}#{size > 0 ? "_" * size : ""}" @name_map[lpath][object.name] = name end end # @return [String] the filesystem mapped name of a given object. def mapped_name(object) build_filename_map unless @name_map map = @name_map[object.path.downcase] map && map[object.name] ? map[object.name] : object.name.to_s end # 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 = String.new('_') x.each_byte {|b| encoded << ("%X" % b) } encoded end end end end end end yard-0.9.12/lib/yard/serializers/base.rb0000755000004100000410000000615213206751010020074 0ustar www-datawww-data# frozen_string_literal: true module 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) # rubocop:disable Lint/UnusedMethodArgument 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 end yard-0.9.12/lib/yard/serializers/stdout_serializer.rb0000755000004100000410000000202713206751010022732 0ustar www-datawww-data# frozen_string_literal: true module 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)/) do ($& + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n") end end end end end yard-0.9.12/lib/yard/globals.rb0000755000004100000410000000105013206751010016241 0ustar www-datawww-data# frozen_string_literal: true # @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) # rubocop:disable Style/MethodName if name.nil? name = namespace namespace = nil end 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.9.12/lib/yard/config.rb0000755000004100000410000002241613206751010016074 0ustar www-datawww-data# frozen_string_literal: true module 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 => e log.error "Invalid configuration file, using default options." log.backtrace(e) 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 # Load gem plugins if :load_plugins is true def self.load_gem_plugins return true unless options[:load_plugins] require 'rubygems' result = true YARD::GemIndex.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 unless 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.error "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.delete('/') # Security sanitization name = "yard-" + name unless name =~ YARD_PLUGIN_PREFIX name end # Temporarily loads .yardopts file into @yardopts def self.with_yardopts 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.9.12/lib/yard/code_objects/0000755000004100000410000000000013206751010016715 5ustar www-datawww-datayard-0.9.12/lib/yard/code_objects/constant_object.rb0000755000004100000410000000073213206751010022426 0ustar www-datawww-data# frozen_string_literal: true module YARD::CodeObjects register_separator NSEP, :constant # 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 end yard-0.9.12/lib/yard/code_objects/namespace_mapper.rb0000755000004100000410000000662013206751010022551 0ustar www-datawww-data# frozen_string_literal: true module YARD module CodeObjects # This module controls registration and accessing of namespace separators # for {Registry} lookup. # # @since 0.9.1 module NamespaceMapper # @!group Registering a Separator for a Namespace # Registers a separator with an optional set of valid types that # must follow the separator lexically. # # @param sep [String] the separator string for the namespace # @param valid_types [Array] a list of object types that # must follow the separator. If the list is empty, any type can # follow the separator. # @example Registering separators for a method object # # Anything after a "#" denotes a method object # register_separator "#", :method # # Anything after a "." denotes a method object # register_separator ".", :method def register_separator(sep, *valid_types) NamespaceMapper.invalidate valid_types.each do |t| NamespaceMapper.rev_map[t] ||= [] NamespaceMapper.rev_map[t] << sep end NamespaceMapper.map[sep] ||= [] NamespaceMapper.map[sep] += valid_types end # Clears the map of separators. # # @return [void] def clear_separators NamespaceMapper.invalidate NamespaceMapper.map = {} NamespaceMapper.rev_map = {} end # Gets or sets the default separator value to use when no # separator for the namespace can be determined. # # @param value [String, nil] the default separator, or nil to return the # value # @example # default_separator "::" def default_separator(value = nil) if value NamespaceMapper.default_separator = Regexp.quote value else NamespaceMapper.default_separator end end # @!group Separator and Type Lookup Helpers # @return [Array] all of the registered separators def separators NamespaceMapper.map.keys end # @return [Regexp] the regexp match of all separators def separators_match NamespaceMapper.map_match end # @param sep [String] the separator to return types for # @return [Array] a list of types registered to a separator def types_for_separator(sep) NamespaceMapper.map[sep] end # @param type [String] the type to return separators for # @return [Array] a list of separators registered to a type def separators_for_type(type) NamespaceMapper.rev_map[type] end # Internal methods to act as a singleton registry class << self # @!visibility private # @return [Hash] a mapping of types to separators def map @map ||= {} end # @return [Hash] a reverse mapping of separators to types def rev_map @rev_map ||= {} end # Invalidates all separators # @return [void] def invalidate @map_match = nil end # @return [Regexp] the full list of separators as a regexp match def map_match @map_match ||= @map.keys.map {|k| Regexp.quote k }.join('|') end # @return [String] the default separator when no separator can begin # determined. attr_accessor :default_separator end end end end yard-0.9.12/lib/yard/code_objects/root_object.rb0000755000004100000410000000101013206751010021546 0ustar www-datawww-data# frozen_string_literal: true module 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 end yard-0.9.12/lib/yard/code_objects/class_object.rb0000755000004100000410000001202313206751010021676 0ustar www-datawww-data# frozen_string_literal: true module YARD::CodeObjects register_separator NSEP, :class # 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.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 #{inspect}" @superclass = P("::Object") raise ArgumentError, msg end end end end yard-0.9.12/lib/yard/code_objects/macro_object.rb0000755000004100000410000001652413206751010021704 0ustar www-datawww-data# frozen_string_literal: true require '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) find(name) || create(macro_name, data, method_object) 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 = '') # rubocop:disable Lint/UnusedMethodArgument macro_data = macro_data.all if macro_data.is_a?(Docstring) macro_data.gsub(MACRO_MATCH) do escape = $1 first = $2 || $5 last = $4 rng = $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) # rubocop:disable Lint/UnusedMethodArgument 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 = '') # rubocop:disable Lint/UnusedMethodArgument 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 end yard-0.9.12/lib/yard/code_objects/proxy.rb0000755000004100000410000001675113206751010020440 0ustar www-datawww-data# frozen_string_literal: true module YARD module CodeObjects # A special type of +NoMethodError+ when raised from a {Proxy} class ProxyMethodError < NoMethodError; end # @private PROXY_MATCH = /(?:#{NSEPQ}|#{ISEPQ}|#{CSEPQ})([^#{Regexp.quote( (NSEP + ISEP + CSEP).split('').uniq.join )}]+)$/ # 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 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 =~ PROXY_MATCH @orignamespace = namespace @origname = name @imethod = true if name.include? ISEP namespace = Proxy.new(namespace, $`) unless $`.empty? name = $1 else @orignamespace = nil @origname = nil @imethod = 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) || @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}" : @name end # Returns a text representation of the Proxy # @return [String] the object's #inspect method or P(OBJECTPATH) def inspect to_obj ? to_obj.inspect : "P(#{path})" 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 to_obj ? to_obj.path : proxy_path end alias to_s path alias to_str path alias title path # @return [Boolean] def is_a?(klass) to_obj ? to_obj.is_a?(klass) : self.class <= klass end # @return [Boolean] def ===(other) to_obj ? to_obj === other : self.class <= other.class 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 to_obj ? to_obj.class : Proxy 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 to_obj ? to_obj.type : @type || :proxy 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) to_obj ? to_obj.respond_to?(meth, include_private) : super 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 to_obj to_obj.__send__(meth, *args, &block) else log.warn "Load Order / Name Resolution Problem on #{path}:\n" \ "-\n" \ "Something is trying to call #{meth} on object #{path} before it has been recognized.\n" \ "This error usually means that you need to modify the order in which you parse files\n" \ "so that #{path} is parsed before methods or other objects attempt to access it.\n" \ "-\n" \ "YARD will recover from this error and continue to parse but you *may* have problems\n" \ "with your generated documentation. You should probably fix this.\n" \ "-\n" 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 @obj = Registry.resolve(@namespace, (@imethod ? ISEP : '') + @name.to_s, false, false, @type) if @obj 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 =~ CONSTANTSTART @origname else [namespace.path, @origname].join end elsif name.to_s =~ CONSTANTSTART name.to_s else # class meth? [namespace.path, name.to_s].join(CSEP) end end end end end yard-0.9.12/lib/yard/code_objects/module_object.rb0000755000004100000410000000127213206751010022062 0ustar www-datawww-data# frozen_string_literal: true module YARD::CodeObjects register_separator NSEP, :module # 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.9.12/lib/yard/code_objects/extended_method_object.rb0000755000004100000410000000144113206751010023733 0ustar www-datawww-data# frozen_string_literal: true module 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 end yard-0.9.12/lib/yard/code_objects/extra_file_object.rb0000755000004100000410000000666713206751010022734 0ustar www-datawww-data# frozen_string_literal: true module 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 when /^\s*\s*$/ # Ignore HTML comments 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 end yard-0.9.12/lib/yard/code_objects/class_variable_object.rb0000755000004100000410000000051513206751010023546 0ustar www-datawww-data# frozen_string_literal: true module YARD::CodeObjects register_separator NSEP, :class_variable # 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 end yard-0.9.12/lib/yard/code_objects/method_object.rb0000755000004100000410000001376313206751010022065 0ustar www-datawww-data# frozen_string_literal: true module YARD::CodeObjects register_separator CSEP, :method register_separator ISEP, :method # 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 @scope = :class if @scope == :module 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 && info[:write] == self ? true : false end # @return [Boolean] whether the method is a reader attribute # @since 0.5.3 def reader? info = attr_info info && info[:read] == self ? true : false end # Tests if the object is defined as an attribute in the namespace # @return [Boolean] whether the object is an attribute def is_attribute? info = attr_info if info read_or_write = name.to_s =~ /=$/ ? :write : :read info[read_or_write] ? true : false else false end 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.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 ||= !namespace || namespace.path == "" ? sep + super : super 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.9.12/lib/yard/code_objects/base.rb0000755000004100000410000005425713206751010020174 0ustar www-datawww-data# frozen_string_literal: true module 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 << push end extend NamespaceMapper # 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 the beginning of a constant CONSTANTSTART = /^[A-Z]/ # Regular expression to match namespaces (const A or complex path A::B) NAMESPACEMATCH = /(?:(?:#{NSEPQ}\s*)?#{CONSTANTMATCH})+/ # Regular expression to match a method name METHODNAMEMATCH = %r{[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 = ["ArgumentError", "ClosedQueueError", "EncodingError", "EOFError", "Exception", "FiberError", "FloatDomainError", "IndexError", "Interrupt", "IOError", "KeyError", "LoadError", "LocalJumpError", "NameError", "NoMemoryError", "NoMethodError", "NotImplementedError", "RangeError", "RegexpError", "RuntimeError", "ScriptError", "SecurityError", "SignalException", "StandardError", "StopIteration", "SyntaxError", "SystemCallError", "SystemExit", "SystemStackError", "ThreadError", "TypeError", "UncaughtThrowError", "ZeroDivisionError"] # All builtin Ruby classes for inheritance tree. # @note MatchingData is a 1.8.x legacy class BUILTIN_CLASSES = ["Array", "Bignum", "Binding", "Class", "Complex", "ConditionVariable", "Data", "Dir", "Encoding", "Enumerator", "FalseClass", "Fiber", "File", "Fixnum", "Float", "Hash", "IO", "Integer", "MatchData", "Method", "Module", "NilClass", "Numeric", "Object", "Proc", "Queue", "Random", "Range", "Rational", "Regexp", "RubyVM", "SizedQueue", "String", "Struct", "Symbol", "Thread", "ThreadGroup", "Time", "TracePoint", "TrueClass", "UnboundMethod"] + BUILTIN_EXCEPTIONS # All builtin Ruby modules for mixin handling. BUILTIN_MODULES = ["Comparable", "Enumerable", "Errno", "FileTest", "GC", "Kernel", "Marshal", "Math", "ObjectSpace", "Precision", "Process", "Signal"] # 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. # # == Separators # Custom classes with different separator tokens should define their own # separators using the {NamespaceMapper.register_separator} method. The # standard Ruby separators have already been defined ('::', '#', '.', etc). # # @abstract This class should not be used directly. Instead, create a # subclass that implements {#path}, {#sep} or {#type}. You might also # need to register custom separators if {#sep} uses alternate separator # tokens. # @see Registry # @see #path # @see #[]= # @see NamespaceObject # @see NamespaceMapper.register_separator 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, *) 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 : (defined?(@name) && @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 @docstring = Docstring === comments ? comments : Docstring.new(comments, self) 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 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 suffix = %w(. :).include?(common[-1, 1]) || other[common.size, 1] == '#' ? '' : '(::|\.)' 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) options = options.merge(:type => type) unless options[:type] 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 parent namespace alias 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 = 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.9.12/lib/yard/code_objects/namespace_object.rb0000755000004100000410000001635513206751010022541 0ustar www-datawww-data# frozen_string_literal: true module YARD::CodeObjects register_separator NSEP, :namespace default_separator NSEP # 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 # @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 unless 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.9.12/lib/yard/docstring_parser.rb0000755000004100000410000002646613206751010020210 0ustar www-datawww-data# frozen_string_literal: true require '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) @text = text.strip call_directives_after_parse post_process 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 = String.new("") indent = content.first[/^\s*/].length last_indent = 0 orig_indent = 0 directive = false last_line = "" tag_name = nil tag_buf = [] (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 = nil tag_buf = [] directive = false orig_indent = 0 end # Found a meta tag if line =~ META_MATCH directive = $1 tag_name = $2 tag_buf = [($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 docstring << "\n" end last_indent = indent last_line = line end docstring end # @!group Parser Callback Methods # Call post processing callbacks on parser. # This is called implicitly by parser. Use this when # manually configuring a {Docstring} object. # # @return [void] def post_process call_after_parse_callbacks 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 # 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) 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.is_alias? 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 private def namespace object && object.namespace end def detect_reference(content) if content =~ /\A\s*\(see (\S+)\s*\)(?:\s|$)/ path = $1 extra = $' [CodeObjects::Proxy.new(namespace, path), extra] else [nil, content] end end # @!group Parser Callback Methods # Calls the {Tags::Directive#after_parse} callback on all the # created directives. def call_directives_after_parse directives.each(&:after_parse) end # Calls all {after_parse} callbacks def call_after_parse_callbacks self.class.after_parse_callbacks.each do |cb| cb.call(self) end end # Define a callback to check that @see tags do not use {}. after_parse do |parser| next unless parser.object parser.tags.each_with_index do |tag, i| next if tag.is_a?(Tags::RefTagList) # we don't handle this yet next unless tag.tag_name == "see" next unless "#{tag.name}#{tag.text}" =~ /\A\{.*\}\Z/ infile_info = "\n in file `#{parser.object.file}' " \ "near line #{parser.object.line}" log.warn "@see tag (##{i + 1}) should not be wrapped in {} " \ "(causes rendering issues): #{infile_info}" end end end end yard-0.9.12/lib/yard/registry.rb0000755000004100000410000004021413206751010016473 0ustar www-datawww-data# frozen_string_literal: true require '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(File.join(Config::CONFIG_DIR, '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) specs = YARD::GemIndex.find_all_by_name(gem, ver_require) return if specs.empty? result = nil specs.reverse.each do |spec| if gem =~ /^yard-doc-/ path = File.join(spec.full_gem_path, DEFAULT_YARDOC_FILE) result = File.exist?(path) && !for_writing ? path : nil result ? break : next end if for_writing result = global_yardoc_file(spec, for_writing) || old_global_yardoc_file(spec, for_writing) || local_yardoc_file(spec, for_writing) else result = local_yardoc_file(spec, for_writing) || global_yardoc_file(spec, for_writing) || old_global_yardoc_file(spec, for_writing) end break if result end result 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 # Creates a pessmistic transactional lock on the database for writing. # Use with {YARD.parse} to ensure the database is not written multiple # times. # # @see locked_for_writing? def lock_for_writing(file = yardoc_file, &block) thread_local_store.lock_for_writing(file, &block) end # (see Serializers::YardocSerializer#locked_for_writing?) def locked_for_writing?(file = yardoc_file) thread_local_store.locked_for_writing?(file) 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(&: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 [] 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) thread_local_resolver.lookup_by_path name, :namespace => namespace, :inheritance => inheritance, :proxy_fallback => proxy_fallback, :type => type 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 path = [namespace.path, name].join(s) if namespace != root 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.doc_dir yfile = spec.doc_dir(DEFAULT_YARDOC_FILE) if for_writing if File.writable?(path) || (!File.directory?(path) && File.writable?(File.dirname(path))) return yfile end elsif !for_writing && File.exist?(yfile) return yfile end end def old_global_yardoc_file(spec, for_writing = false) path = spec.full_gem_path yfile = File.join(path, DEFAULT_YARDOC_FILE) return yfile if for_writing && File.writable?(path) return yfile if !for_writing && File.exist?(yfile) 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 # @since 0.9.1 def thread_local_resolver Thread.current[:__yard_resolver__] ||= RegistryResolver.new end end end end yard-0.9.12/lib/yard/cli/0000755000004100000410000000000013206751010015041 5ustar www-datawww-datayard-0.9.12/lib/yard/cli/diff.rb0000755000004100000410000002037513206751010016310 0ustar www-datawww-data# frozen_string_literal: true require '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 elsif load_gem_data(gemfile) log.info "Found #{gemfile}" all_objects else log.error "Cannot find gem #{gemfile}" nil 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(&: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}" next unless File.directory?(yardoc) Registry.load_yardoc(yardoc) Registry.load_all return true end # Next check installed RubyGems gemfile_without_ext = gemfile.sub(/\.gem$/, '') log.info "Searching for installed gem #{gemfile_without_ext}" YARD::GemIndex.each.find do |spec| next unless spec.full_name == gemfile_without_ext yardoc = Registry.yardoc_file_for_gem(spec.name, "= #{spec.version}") if yardoc 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 # 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 nil # noop end false end def expand_and_parse(gemfile, io) dir = expand_gem(gemfile, io) generate_yardoc(dir) cleanup(gemfile) end def generate_yardoc(dir) 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| next unless pkg.full_name == 'data.tar.gz' Zlib::GzipReader.wrap(pkg) do |gzio| tar = Gem::Package::TarReader.new(gzio) tar.each do |entry| file = File.join(tmpdir, entry.full_name) FileUtils.mkdir_p(File.dirname(file)) File.open(file, 'wb') do |out| out.write(entry.read) begin out.fsync rescue NotImplementedError nil # noop end end end end break 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.9.12/lib/yard/cli/display.rb0000755000004100000410000000363713206751010017047 0ustar www-datawww-data# frozen_string_literal: true module 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?(&: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.9.12/lib/yard/cli/markup_types.rb0000755000004100000410000000207613206751010020121 0ustar www-datawww-data# frozen_string_literal: true module 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) # rubocop:disable Lint/UnusedMethodArgument 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 log.puts " Providers: #{libs.join(" ")}" unless libs.empty? if exts[name] log.puts " Extensions: #{exts[name].map {|e| ".#{e}" }.join(" ")}" end log.puts end end end end end yard-0.9.12/lib/yard/cli/command_parser.rb0000755000004100000410000000520613206751010020366 0ustar www-datawww-data# frozen_string_literal: true module 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.empty? || args.first =~ /^-/ command_name = self.class.default_command else command_name = args.first.to_sym args.shift end if commands.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(&: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.9.12/lib/yard/cli/yardoc.rb0000755000004100000410000006632313206751010016664 0ustar www-datawww-data# frozen_string_literal: true require '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 # @return [String] the current locale attr_accessor :locale 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 +yard help doc+ 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 # @return [Boolean] whether yard exits with error status code if a warning occurs attr_accessor :fail_on_warning # 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 @fail_on_warning = false if defined?(::Encoding) && ::Encoding.respond_to?(:default_external=) utf8 = ::Encoding.find('utf-8') ::Encoding.default_external = utf8 unless ::Encoding.default_external == utf8 ::Encoding.default_internal = utf8 unless ::Encoding.default_internal == utf8 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.empty? || !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 if save_yardoc Registry.lock_for_writing do YARD.parse(files, excluded) Registry.save(use_cache) end else YARD.parse(files, excluded) end 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 abort if fail_on_warning && log.warned 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 = Parser::SourceParser::DEFAULT_PATH_GLOB if files.empty? 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 = false lvl = 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 extra_file_valid?(file) options.files << CodeObjects::ExtraFileObject.new(file) end end end # @param file [String] the filename to validate # @param check_exists [Boolean] whether the file should exist on disk # @return [Boolean] whether the file is allowed to be used def extra_file_valid?(file, check_exists = true) if file =~ %r{^(?:\.\./|/)} log.warn "Invalid file: #{file}" false elsif check_exists && !File.file?(file) log.warn "Could not find file: #{file}" false else true 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 = [] exprs << "#{apis.uniq.inspect}.include?(@api.text)" unless apis.empty? unless hidden_apis.empty? exprs << "!#{hidden_apis.uniq.inspect}.include?(@api.text)" end exprs = !exprs.empty? ? [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| excluded << path end opts.on('--fail-on-warning', 'Exit with error status code if a warning occurs') do self.fail_on_warning = true 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 extra_file_valid?(readme) options.readme = CodeObjects::ExtraFileObject.new(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| from, to = *asset.split(':').map {|f| File.cleanpath(f, true) } to ||= from if extra_file_valid?(from, false) && extra_file_valid?(to, false) 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 Encoding.default_internal = 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('--no-progress', 'Don\'t show progress bar') do log.show_progress = 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.9.12/lib/yard/cli/command.rb0000755000004100000410000000606313206751010017014 0ustar www-datawww-data# frozen_string_literal: true require '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 end yard-0.9.12/lib/yard/cli/graph.rb0000755000004100000410000000746413206751010016505 0ustar www-datawww-data# frozen_string_literal: true module 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) @objects = args.first ? args.map {|o| Registry.at(o) }.compact : [Registry.root] end end end end yard-0.9.12/lib/yard/cli/help.rb0000755000004100000410000000074313206751010016325 0ustar www-datawww-data# frozen_string_literal: true module 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) cmd = args.first && CommandParser.commands[args.first.to_sym] if cmd cmd.run('--help') else log.puts "Command #{args.first} not found." if args.first CommandParser.run('--help') end end end end end yard-0.9.12/lib/yard/cli/yri.rb0000755000004100000410000001465013206751010016202 0ustar www-datawww-data# frozen_string_literal: true require '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(File.join(YARD::Config::CONFIG_DIR, '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(File.join(YARD::Config::CONFIG_DIR, '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 return exit(1) end object = find_object(@name) if object print_object(object) else STDERR.puts "No documentation for `#{@name}'" return 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" obj = try_load_object(name, nil) return obj if obj 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) obj = try_load_object(name, path) return obj if obj 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) obj = Registry.at(name) cache_object(name, cache_path) if obj && cache_path obj 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 = [] YARD::GemIndex.each do |spec| yfile = Registry.yardoc_file_for_gem(spec.name) next if yfile.nil? if spec.name =~ /^yard-doc-/ gem_paths.unshift(yfile) else gem_paths.push(yfile) end end @search_paths += gem_paths rescue LoadError nil # noop end # Adds paths in {SEARCH_PATHS_FILE} # @since 0.5.1 def add_default_paths @search_paths.concat(DEFAULT_SEARCH_PATHS) return unless File.file?(SEARCH_PATHS_FILE) paths = File.readlines(SEARCH_PATHS_FILE).map(&:strip) @search_paths.concat(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.9.12/lib/yard/cli/config.rb0000755000004100000410000001437113206751010016644 0ustar www-datawww-data# frozen_string_literal: true module 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 # @return [String, nil] command to use when configuring ~/.gemrc file. # If the string is nil, configuration should not occur. attr_accessor :gem_install_cmd def initialize super self.key = nil self.values = [] self.reset = false self.append = false self.as_list = false self.gem_install_cmd = nil end def description 'Views or edits current global configuration' end def run(*args) optparse(*args) if gem_install_cmd configure_gemrc elsif key if reset || !values.empty? modify_item else view_item end else list_configuration end end private def configure_gemrc return unless gem_install_cmd require 'rubygems' ['install', :install, 'gem', :gem].find do |cmd| conf = Gem.configuration[cmd] || "" next if conf.empty? && cmd != :gem conf = conf.split(/\s+/) conf.delete_if {|c| c =~ /^--(no-)?document\b/ } # scrub doc args conf |= ["--document=#{gem_install_cmd}"] conf = conf.join(' ') Gem.configuration[cmd] = conf Gem.configuration.write log.puts "Updated #{Gem.configuration.path || '~/.gemrc'}: '#{cmd}: #{conf}'" true end end 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 = encode_values current_items = 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 "---------------------------------------------------------" opts.separator "" opts.separator "Configuring RubyGems support:" opts.separator "" opts.separator "YARD can automatically generate the YRI index or HTML" opts.separator "documentation in a `gem install` by adding the following" opts.separator "to your ~/.gemrc file:" opts.separator "" opts.separator " gem: \"--document=yri\"" opts.separator "" opts.separator "Note: you can add 'yard' to also generate HTML docs." opts.separator " You can also add 'ri' to continue generating RDoc." opts.separator "" opts.separator "You can also run the following command to configure this" opts.separator "behavior automatically:" opts.separator "" opts.separator " $ yard config --gem-install-yri" opts.separator "" opts.separator "Add --gem-install-yard to also generate HTML." opts.separator "" opts.separator "---------------------------------------------------------" 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 opts.separator "" opts.separator "Add RubyGems install hook:" opts.on('--gem-install-yri', 'Configures ~/.gemrc to run yri on a gem install') do self.gem_install_cmd = 'yri' if gem_install_cmd != 'yard' end opts.on('--gem-install-yard', 'Configures ~/.gemrc to run yard on a gem install') do self.gem_install_cmd = 'yard' 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 end yard-0.9.12/lib/yard/cli/list.rb0000755000004100000410000000131413206751010016343 0ustar www-datawww-data# frozen_string_literal: true module 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 end yard-0.9.12/lib/yard/cli/i18n.rb0000755000004100000410000000454113206751010016154 0ustar www-datawww-data# frozen_string_literal: true require "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.empty? || !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.9.12/lib/yard/cli/gems.rb0000755000004100000410000000462013206751010016326 0ustar www-datawww-data# frozen_string_literal: true module 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 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) do log.info "Building yardoc index for gem: #{spec.full_name}" Yardoc.run('--no-stats', '-n', '-b', yfile) end end end end def add_gems(gems) 0.step(gems.size - 1, 2) do |index| gem = gems[index] ver_require = gems[index + 1] || ">= 0" specs = YARD::GemIndex.find_all_by_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 += YARD::GemIndex.all if @gems.empty? end end end end end yard-0.9.12/lib/yard/cli/stats.rb0000755000004100000410000001607713206751010016542 0ustar www-datawww-data# frozen_string_literal: true module 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, :attributes, :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 = 0 @undocumented = 0 meths = methods.map(&: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) } total = if @undocumented == 0 100 elsif @total == 0 0 else (@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:" # array needed for sort due to unstable sort objects = @undoc_list.sort_by {|o| [o.file.to_s, o.path] } max = objects.max {|a, b| a.path.length <=> b.path.length }.path.length if @compact objects.each do |object| log.puts("%-#{max}s (%s)" % [object.path, [object.file || "-unknown-", 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 || "-unknown-"})" 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 attributes def stats_for_attributes objs = all_objects.select {|m| m.type == :method && m.is_attribute? } objs.uniq! {|m| m.name.to_s.gsub(/=$/, '') } undoc = objs.select {|m| m.docstring.blank? } @undoc_list |= undoc if @undoc_list output "Attributes", objs.size, undoc.size end # Statistics for methods def stats_for_methods objs = all_objects.select {|m| m.type == :method } objs.reject!(&:is_alias?) objs.reject!(&:is_attribute?) undoc = objs.select {|m| m.docstring.blank? } @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) data = if undoc ("%5s (% 5d undocumented)" % [data, undoc]) else "%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.9.12/lib/yard/cli/yardopts_command.rb0000755000004100000410000000665313206751010020746 0ustar www-datawww-data# frozen_string_literal: true require '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.9.12/lib/yard/cli/server.rb0000755000004100000410000002202713206751010016702 0ustar www-datawww-data# frozen_string_literal: true module 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 = args[index] dir = 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, Registry::DEFAULT_YARDOC_FILE) 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' YARD::GemIndex.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| 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.casecmp('webrick') == 0 self.adapter = YARD::Server::WebrickAdapter elsif adapter.casecmp('rack') == 0 self.adapter = YARD::Server::RackAdapter else self.adapter = eval(adapter) # rubocop:disable Lint/Eval 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 opts.on('--fork', 'Use process forking when serving requests') do options[:use_fork] = true end common_options(opts) opts.on('-e', '--load FILE', 'A Ruby script to load before the source tree is parsed.') do |file| 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 # This is not necessary but makes for a better first-run experience libver = libraries.empty? ? nil : libraries.values.first.first generate_doc_for_first_time(libver) if libver && !libver.ready? 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(%r{^#{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.9.12/lib/yard/server.rb0000755000004100000410000000062113206751010016127 0ustar www-datawww-data# frozen_string_literal: true module 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) static_paths = Commands::StaticFileCommand::STATIC_PATHS static_paths.push(path) unless static_paths.include?(path) end end end yard-0.9.12/lib/yard/autoload.rb0000755000004100000410000004000313206751010016427 0ustar www-datawww-data# frozen_string_literal: true # @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 :NamespaceMapper, __p('code_objects/namespace_mapper') 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 :CONSTANTSTART, __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 :PrivateClassMethodHandler, __p('handlers/ruby/legacy/private_class_method_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 :DecoratorHandlerMethods, __p('handlers/ruby/decorator_handler_methods') 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 :PrivateClassMethodHandler, __p('handlers/ruby/private_class_method_handler') autoload :PrivateConstantHandler, __p('handlers/ruby/private_constant_handler') autoload :PublicClassMethodHandler, __p('handlers/ruby/public_class_method_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') autoload :TokenResolver, __p('parser/ruby/token_resolver') 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 :RootRequestCommand, __p('server/commands/root_request_command') autoload :SearchCommand, __p('server/commands/search_command') autoload :StaticFileCommand, __p('server/commands/static_file_command') autoload :StaticFileHelpers, __p('server/commands/static_file_helpers') 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 :TypesExplainer, __p('tags/types_explainer') 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 :GemIndex, __p('gem_index') autoload :Logger, __p('logging') autoload :Options, __p('options') autoload :Registry, __p('registry') autoload :RegistryResolver, __p('registry_resolver') autoload :RegistryStore, __p('registry_store') autoload :StubProxy, __p('serializers/yardoc_serializer') autoload :Verifier, __p('verifier') end undef __p yard-0.9.12/lib/yard.rb0000755000004100000410000000420713206751010014625 0ustar www-datawww-data# frozen_string_literal: true module YARD # The root path for YARD source libraries ROOT = File.expand_path(File.dirname(__FILE__)) require File.join(YARD::ROOT, 'yard', 'version') require File.join(YARD::ROOT, 'yard', 'autoload') # The root path for YARD builtin templates TEMPLATE_ROOT = File.join(ROOT, '..', 'templates') # @deprecated Use {Config::CONFIG_DIR} CONFIG_DIR = Config::CONFIG_DIR # 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' @windows = ::RbConfig::CONFIG['host_os'] =~ /mingw|win32|cygwin/ ? true : false 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 = YARD.ruby18? RUBY19 = 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') require File.join(YARD::ROOT, 'yard', 'globals') # Load YARD configuration options (and plugins) YARD::Config.load yard-0.9.12/docs/0000755000004100000410000000000013206751010013515 5ustar www-datawww-datayard-0.9.12/docs/CodeObjects.md0000755000004100000410000001310013206751010016221 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.9.12/docs/Templates.md0000755000004100000410000004537413206751010016015 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 overridden 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.9.12/docs/images/0000755000004100000410000000000013206751010014762 5ustar www-datawww-datayard-0.9.12/docs/images/tags-class-diagram.png0000755000004100000410000002177113206751010021146 0ustar www-datawww-data‰PNG  IHDRgSz‡A˜äPLTEÿÿÿfff999Žf99fµÚŽÙÚŽ¶f999ff99ŽŽff9ŽfŽÙÿ¶¶ÿ¶ŽfŽ9fff9ŽŽ9µÿ¶ŽÚ¶fŽŽ¶ÚŽÙ¶ÚÿÚ8eÙÿÚV‚f9ŽŽŽ¶Že›e‚ºŽ8yyHI8)µÿÚÙÚ›f9ŽÚ9ŽÚÿ¶ÿÿÿ¶fÿÿÚ¶ff¶ÿfÚŽ99Ž9ÿÿ¶f¶ÿÚŽ9ŽÚÿÿÀÀÀf9f¶9f99Ž99O10eµÚff9999µ¶f9fffffÙ¶fóÐ>-"ÐIDATx^ìÛénÛ0…Q=ÏPûêµûÞ÷ŸÎŒY¡@ÄYhÅw„ ý ÆŽ…[<"¯ ¹ ‘â>áï‡3‚3œá gDN§Sñ¶ÁÁÎp†3œáŒà g8ÃÁÎp†³})"C½nt"ý€FÞ¿ÓE¶'…íßœá,í¼B[·c±u¶œwÎmÛ¿18ÃYœY¥LU;ÛpE$èf(º¡nä‹n~_œù‘éÔ¥µý£ß§ä>”Ÿ?ŽË9à,œé7]M•ͳý÷Ê.£³«yâ†-ö5NÕrÖ‘8úoã,œ)µâtüu³™ª­3‘õ(jŠÆŒ©]êÚ+5œ¥Ã<Å|ž•CÝm]hÅ£ñÊ™­î¬w.©à g½yј³qJ¾nÆ£Ä<Óãog‰àÌèèjfܙɚ*׳qlÃŽ}qkg˜ÖtpÆçg®½Ï³vù¥× _Í™_ýpgñÈïRXPÃåÎünœá,s\[æà g£ 5Î^œñ|gg8ÃÎp†3‚3œá g8“ÿ%í gLGp†3œ½*gÌ3æÙ‹¦3Îp†3œá g8ÃÎRÕFúFÎrgœÝ'̳Ÿ¥/DO•×¥s”£q†³ØÐê¿ué åhœá,¬ÂX—ÎPŽÆÎúXˆ^ëÒËÑ8cž­ué<åhœñþÌgX¬K¿a9g8Mø÷ÿÍÝZ—Þ”£q†³Ìåhœáì‘ËÑ8ÃÏ7 Îp†3œá gw ýæ¡¿‰³g†~ó g8ëúöcu#€ýûÄ'…í,–Äsœáì{çúäF­qr“lž< pC py|ñlÖëÁ°“ÝÊŠªýÿÿ ޤÞikשʸ,MÔ*g'zm†_klÜudÝ;™ÈûãŒú£lwéÒü‹Ž1´É²oƒ³È÷¡Ïîý×Ì))¶%¹~òÀ¼›á†Äïwa®ÃßãØþðé[ò…ëÝ^qvŽúÚ¶ýUKœá_¿î¢`i>§ÿ¼5^ ¥>X‡Œê]¸PŸÚ—Ì\»YïGÍÕ ž °Õ] ÉØ½’³ÐÚgËE(Ud«àßìÃ)‘+v -d Cì… #í²·!Ψ¿Ë „¶Ž\A¯mïg|nNQc« ¾ˆÌí±ÖmW²„!÷7ÿÆ{àŒj¥þÒMì!OðÇçæ1>-µÅ?˜ã_ßõ—Û­iy¹Á8²„!;ö3ô¶¶ŸQŸ<Ž‚…<­zå~¶´Z+œ±ØÎc¯h¡[¦ßN¾´K¨Å?«.\Ȇìx–õ¶Ãõ:ý£·´C¯ä,Úgü`ûÙ—QuëÅâპòŒ~bÎNCBû§ïÇŸ7³Þ†>oR‘&ÈÓ¡Wrfž·Å‹qöP€0§·În¶º1]Bž‰¸ñçÍãNœíø''Å8ËŸn¨÷ŸM/\¡nÎ(À ‡¢ —7ñXPhîUÃp£ Ÿ7Ö‹‘Y-Á”‡ç JÉŸn¨ÎÆv‹_¸Bs~ {³ÎÆ¥gPJþtCM~Òœ}¸ìÖ±Ÿf5úÖä×gòk,ÎTÄÙ~".ÎTÄÙÞHó9SgÓI+í?CwåF4q6´²þ3öù ̓3ªµ€µ¬â¬Ø‡öŸ!ÄY\â,vŸ  Ö4»Õ¾­ZΨÖÖ²Š÷³CûÏàzÁiÚ0kÍÁˆFÎÆjýö»Ö²ZߟÞ?–HÝhËÝŽ­RΨÖÖ²Z?oòŸÅçJZ"u£-wÌÁˆFÎÆj-`-«óÿŸ•ñŸ!¾½vígXË1¢Uÿܼ|TÞZVž³E)ÿBp ¾?Ã@kvhÕrFµ´–•笼ÿ ¦r,n:a˜»iF4r6Vk k™òŸM_"_ªRΨÖiÖ2q6ÙÆ%æoD#g¥¬eòɯQÌZ&ÎÄ™òk¨èüÍ*9SÑ~&ÎÄ™òŸùñXõ=hâLùϦsÆÚlóŸý ÅÎW§üg ³8nÃxñG´ý?TÚ|òŸ‰³ûÏB4ÌÆ1Þ‚&¹=Ú\òŸýt}§'Ô}å?ìa\ÆmbzÑa¤ïA«?ÿÅæUçoîÕ†YÃ8vaø<µªãA›Kþ3ŠÍêŒ9«1ÿfa\&o,°º‰³Ú\òŸ‘3G¨så¬Òüg˜5ŒCÙr¢ÝŸºŽm.ùÏÈ™+ÔéEþ3ò‚YÇxHœüô¯­êxÐf’ÿŒœyBPä?+œ ­|þ3ræ uoEþ3§kV4rV•rä×/È?(Wœ©È¯!ÎÄ™8g⬵"Îä?ógÐ1Áµ&Îä?Ûg¬•ãŒð{YõŽ‚ýSÎÞå Öw†–ÿì3N²•†ßæøn ¸ÖJr¶¼éÌú˜uÈçLþ³á•¯„ ˆßM)ךï ÊDiÂúå×A Ðy‚Ì9@Ï$Hüdz4H5 „$1Çýí¿5¶½æº£Ð¸ ûÏÈY¾R~° |7e\k>gƒ(™ìŒZ Fî*õrÃQ<{0ó8A1¥š²¨Ùsèrc?“˜cÐÍCÃñ ûÏ8#_)?X¾›B®5ßQ29µ0ÖF¦ÛÝcÆgeÝ!ǶTcµaZƻڲƒš¿+íúÏÈY¾&äûY!ך¿ŸA”yö@háŽFh…I¹¨8 Aò´ã¥š¦ÜŸ‚ÔbÛgÍ_ã[öŸqF¶&`.ž=¥\k>g%÷3tŽ42h®Ï=k²ýØ-™TC5ìO)#̪mÛœ1´Õðþ¬qÿÙÑ0#[ À|7…\k¾_#%Å‘}†)õ|[1ãlƒë>úS4JÕþloúFRj#gãÐòŸÍÁµæsQòµ0xÓF§o®n¬Bγ 2[šQóôØNÐ’éÃÚ2Î:i_þ3§§€k­v¿ÆÅÕ®6ù5ä× F&–5CdmâLœUSÄ™8g*âLœ‰3ùÏüIScâLþ36L>§ó7©¨»zceßEùÏ8) ˆ5q™›Õž¿9’Í!5¤üg0³` DœpæfÍçˆÁ˜y½Ál†ýleƒÎ¡³ýå?Kf¬ˆÎܬöüMJ,sÕ •¸ïAgû/Ê–Ì,,a&œ¹Yóù›ö"W”%*6ŽÊÝsQþ3˜Y°#ºgnÎï¹™sFY¢bò¡r÷\”ÿ 3°"N8s³Þó7GœA–¨åì/Sþ3N ƬˆÎܬüüMrEY¦JÌÿLåî½(ÿÙÅÖ˜¾þó7ÉôF寠V:èlßEùÏ`\Áœcòk”áLEœ‰3q&ÎTtþ¦8;ôðçGRÊs¦"Îæï?óÓP±°°‰³šýg¥8ãR‡àLe^þ3?Ýo‡œ2ý"Mµ°‰³üg~º34bH–~©+`agsõŸùéζf DšœüLœ5â?óÓqáŒ3DšhagøÏütg\8ã ‘&ZØÄY+þ3?ÝÞâ ‘¦ZØÄY þ3?Ý1d‹3Dšjag øÏªO~&Îæï?›žîÌ·°•ãLœ©Ì›3q&ÎTÄ™8gâLœ©ˆ3ùÏü¬¡}Ñí¶2ÑÇ&Îä?›ÀÙ|_âLþ3?ÄP³ Žˆƒù•ÖK÷Oq&ÿ™5LÈÒEáââ)Îä?óC † –qæúØÄ™üg~.Í`ìâ)Îä?óC † FμC<Å™üg~Ô0ÁBuÜÖ¼C<Å™üg~Ô0ÁÂåM|ÚŸ:‡xŠ3ùÏâck‹3ùÏ&„˜äc«‘3ù5ä×Pù‡;&@h3Ø?—-<>3Æèä„sþ t6 ÐÙ@Ù¹—Ý´8£Î¥­ò*l§øj.ê*­”÷ ÈGÄÉ.Ö @ç†-Ò§‘añ+ð;t†ÎÐè ÎÐ:¡3Ð:Cg 3t†Î²î´ç‡ÎÐYÚ(K3li²lÚ"KŸgóiß‘†ûÆÑ¾²yß_;î•ÍçÓ@gcOé:í¯}Ø+›Í§-‚ÎîvSgÓdÙq¯ìë|Úr8Ïnêù¸Ù§ù´ep6üý™æ±Vóa¶OóiKá÷æ´ªøa˜m\)›Í§1ìÎÐ:¡3t:Cg 3t†Î@gè t†ÎÐè ¡3Ð:¡3t:Cg 3t†Î@gè bvÉâøºlè bz^osfÏ:–¯6Ï&­3Õ\x‡“µõ8£ß<*–ªB½çÉ&áÌŽu8»(D‘dz3×úç€Ø×¯6mΞMÄY8G{î?gpæi€HÑ}»I<óc-Zì|çLÎ5œùþ¼ÅU9êÆ³€÷Êgä›!|…—H /…Ÿîý™vú±-v{ÕâL·`I¾HÒ‰]ÎtÂñÞŸQ³GÎ< $óé¢(>}\+üMÒo6ÇZ´èk¢Ñ9SÎÐÎ7õø•Ó×Ó.gWÚ}¬ù&‰b°ïídÄ™+p–h}‰_ÎÒÒeŠB1ƒÔÊÿô÷€Ÿ›r¦¢pgø5à¬GŸgœÁœÙxz鎆¢ø«x38ƒ³Òï—•ñ‹/+T7$gpgâJíl¢Œo>ݽÀ«8Ȧͼ³ÌNÒâh8ƒ³*Ö S=:Å³Ý ¼:gýýgÚÌ;Ëü¤#âŒû³Z]§ð2ÎÒ¯yÎúøÏdkü>ÖZÖYö‡ð­'ÏÏŸ¼›Ê¦æÞµ•38³pµ(¤Rœå ¼öçÌýgî( ~ká-ç,ÓÁõ¸ÖÂljæ]ûx9ƒ³€ÕJñÌó€ ¼Š³þ³ÆQ&Ø#vyg™ýÝîõø˜9ƒ³Ó·ñþLdgi×{ô¥?,®Ö2EÎF±JËh-Zx[ µJ?µ‰:gVëç#‚³| Ù¹ZâBî«Ò¼Ttgpÿ™ê”©— ?o^4-¤íV4n êmë§ŒY ÎÒbñlTýî2²Om_«¶ºDÏB_vÙÞÜvúZ×ó…å›aa½à¯9Ó)¢è/†ŽÕI³ýÒžÍjp–!4B‡ïÐÄSRè°H–/¢ÿùtÎÒ:e⾿M?u ³œ¥1ÄË&Û +nJµü, $6ÕÝ–3¯S&Îú[ÑôS‡1«ÁYÙFR É~ 8ó@’Æ8ƒ3üpgpvÄ‚38ãù€þÞ‘þÕÐà ÿYÝ«¡Áœ¥u\z̳™1˜Áœ¹ÿ,3Ïæ±TCƒ³Á5¬ÿ,?ÏfÿjhpF¿ÙcžÍœÁ ÎàÌÒ€!æÙ$žÁYÎ;ÒcžÍ¬Á ÎàÌÒ€^ólæ fpgÒþ«¡Áœ¼œÁ~ 8ƒ38ƒ38ƒ³û+8ƒ38£þ™oha;Òé8ó¥‹fÉ,È* e³‰Ö™f’iüîgøÏ*g"å,_ºÈê"´„3sz,/Ê_i&ÙViŽcâ Îòµ‹„ÈUã?›˜ïL‹3YËr¥‹â<Œ,?ýÓǶ¥6žíÍÌ®½¹Í+=sÅY56;åh8ƒ³´v‘BQówtó ™™ÜùÒE^ôEªÜ‚VÔöcÚ)ÜÞŒU\kdz“ÆçÇâ)åŒçzÖ.Òjx{4·ÌfK´ì÷ÂB ÙÙѪÞÞŒ¶¯å­y56;ζéÇ;PÏÚE£gÀ|g!š8gùÒEÍ×í +µååÔ"gân{3^qͶ…©¹âì˜rDœÁYZ»¨žx<Ë—.jߟuã™5æ÷gÛ›ñÎ×¶#¦uë˜rHÎà¬oí¢je>GÛh;ä÷É•.êæ›éý™¶tTùæöfÂz—3Ñj®8;f§1gÔ.R"x6±DÐ ¡©:Z¦t‘Žøø™ýž˜´|Ó¼ß6¶½™ªoÚø™¹â¬÷´SŽž3r_Å¥‹\ùfðk<`ΊH=J¹òÍôœáÁ¯Š{¬Ãr†ˆg©œÁœÁê=ÿ¦[%:Ûp6¸˜;¯ÃÕÁsYÕ²ÀÕW…ª˜5®/‹gUøÒÊœ_p†në?óªe WfÑiu¢nƒ3Ô£þYx9W^ Í6£9¿à¬‡è7SÎäú² ù:Üùgè–õÏÎT Í·ÕköepÆÜy)gzy™ÆEé¦8C=êŸ9gM%3s}i—RРÒ_p†ðk 8ƒ38ƒ3gpgp†àì¡ Îà ÿYªaçØ„3ügr†˜cÎðŸ}ó]1ÿc=ZŸ|öèK ù›Ólð96á ÿÙ¬ÍÊåÅùf6÷Y7žcÎðŸ-_mžMÔAzY²ÁçØ„3üg§ï¿~µ`^°lð96á ÿY¬k,Îl—4ô›p†ÿLñ*$–«¤ÆØPslÂþ3•;}­Œ_x=²ÑðslÂ~õeR’lè96á Îg“9ó96á á×@Ô?£þµ¿û«Pˆ¹CÁœÁœí ³ÑÞAƒ3TØ{¿B`vo@Cp†ÀìøACp†Pá}¬BTY@Μ!8CΜ!gΜ!gxüÑèð"JpÎà Îà ÁœÁœÁœ!8ƒ38ƒ38ƒ3gpgp†à Îà Îà ΜÁœÁ‚38ƒ38ƒ38CÅ¡t¨k9ü bÒÛ-Ðîa®Îà Îà Îà¬ÿ\[ÅÚ=Ð<0Á™gp¶E1÷9\«¢¨;'ÍÂöúòz*ÿͰœy£EÙ™‹V­¶åí)gpVÆù¬oæH7”Úœi>õ¸²§xVMï«‘IÍ¥²ö—38B lg…ùtÃË,¼«ùtVüó­‰qiqö/ÁÙ3G=Ît<+þ\”§jîßvEP;ÅYÚþQqgú/Q¥x¶þy¢Uã¬ÏìX8ay1g"¬¡mp^Äæ,ŠêÐz|þFñ6mÿØ8ƒ³R'"Iœ ©Iþ+gvLhT{à¬ÔÂ8ÓnÿiÿH8#ž- ©Œñl<ŸV[8³cb`±Îj!ïœiË8Ë·gù$+Ã[Íÿæ)×ðœÅèay€V·õ›vÌߟeâY®}8Ë'Yyμëœ3»ãD‘3‘u6‰=XÂYçØÀù欈gÚ¶œ³lûp¶=ÉúûÛUWXYrµ¼øÇøìÿnr-Ï®æ?‰³LÊÕkül–uŒgJø®Âz[5kÓ¦q;fW4ðøY“ojsþ‹ç›ÎY¶}8Ûžd-”äÕÖ;Ä á¹V'»Ê§\yΆTu¾ˆ3äåíÚÏsg›Y“@_­\˳«LÊuל) †öÃYÚ~ž38;}[.tO$•Æ™çZž]í’rñ÷Í®¸?,«ª4ìFÄ3Ï®vK¹à,ùæzl¤¥Z­\«]í’rÁY"ÆÏNßžo<Ý[µþÚ˜dW™”+ËÙ(ÃÙΆQ>å"žÁÙÐ)œÁ~Z8ƒ38»7‚38ƒ³ª>}?iÌ÷µÛðË®—âÝ4¼Ú^’ó§ã"h> ß­{qæWÐm0m*|QÛúøA­gp [>šv9s¦¶q¶2!Õ­úpæW(mj!ßÀ•>ÊQu œÁÙ [æf[^Ÿ>–Q£k»çFÆ Ñ!ûJfŠ*mÎôy+ÎÒ+øìÑ—1q¾iwýü±k7µ>Ùœ¾ÿ^“#â Î …‰ªT¤Å"2´üd¢…qÖ¼tÎb5Hî?gÔ ®>œ¹93M¹àlçðtP4³?‹?g^²G×°WÎÔ”Ë[…³#à9ÎÒ±+üp–ƒo†×Fã_LÖ'ŸEmC♢lÏFƵŒÅÜåFÀµiƒï1Í“×?f{>$®C62n#õÄ3 Îv·;’æ:êK «î¸-l¤>3Ÿ¨àùúÍ8¼nvÎ|(¾Í™Ô'cñÄ3âYf܆דxæCâΙ› ÜåFÀmxÝïÏ +÷Ñøh¨HÇâá ÎòcðU;ßüMÏ|(^ð7£ñ#©ÏÅÜå‡ËúÅÜm—2ƒ³ÉPcñpg<ïgpgpgpgpgp†ÿ,Õ€^48K…ÿ¬¿ Îà,ÿ¶Lfq5`ø²(ÊY4wDÛ™èkÛž ‡38Ë?-“™­6VÜ8ÓµqmÆ5âœÝî ì‘­jgx ;@Ü×FÛŸ ‡38Ë?=²Õgþ€¸¯¶?gp–{d«-Îüq_m.Îà,ÿöÈV[œùâ­µíυÜåŸÀ¾^mqf¶3yÑüQñQþ¹pž€3“0:Øsá?Þ¼µ_œ ü\8œÁÙgœ!8ƒ3gÎà åç I}@¶èQþL‚3ügyÎò–38C»ÌAróÀù¬0«Ù“çUÿÌj¢Y…´]ËŸÁþ³j\‡ÈŸEk™ùÑšEœcΆþ³tŽM8^øÏ’96álO¢þ™Ï± g{þ³tŽÍágøÏÒ96‡œá?KçØÜ?g¿Æ £ipgyËœ!üÎà ÁÙv!8Cpgÿ†ðŸY)³½r†ðŸY)³½r†ðŸÝÅ|(ÿ™•2Û7gÿ™JLí•3„ÿLŒí3„ÿ¬"ßDøÏîHÿ¯g¨8gèÇCèöœ!8ƒ3g¡ÿVÇ çZ!IEND®B`‚yard-0.9.12/docs/images/overview-class-diagram.png0000755000004100000410000001742413206751010022056 0ustar www-datawww-data‰PNG  IHDRÁaôô{PLTE²²²ÀÀÀÁÁÁÊÊÊÕÕÕßßßêêêõõõÿÿÿc›d[±IDATx^íÝÍŽë6¶6àe$kö}×Äã êμ'5Ý£® HÃû ™­Y÷ºÛƒ&)/É”‹’)–~ü®H”,Ûñ†¤´ùƒÖÁÛOˆí/(Ü0(La S˜Â¦0…)La S˜Â¦0…)La S˜ÂεÑ%Y>Gö!i| ²Œpþï…Ái3lRØ)sa|*¬€tÂò¥Âpá¾ûV…!¦–ðÒ§r* ^Ѽ”û÷‚ ~Äf…#Â^b* «˜¦‹YŠáð’¤Ï€Y¼ ÝÛUâI•e„áÓ5¸¢³F<Séõ²®°Æ„&„” Â+0¤ ’0Ì…Ñd*Ö]ß.Štr!a ‚PÿP|ÿæx¾ÛlB¢¸n’pLª(‚µÁv¢‰VÌK ˆ¿]a×·h<›…7*‘\“süé|w°a3ø¦W£hd† /HŸá5ü3ºßËÇ`œ6Ë ›†«­°N¼3÷¯Ý˜p' l@.Ô¢° …ƒy*Û§bË‹…ô…NÀF…%m£Ü«®jD8e`´¾H95\8œß†°WT¾éÉþ¯Ë…6*œ$S9±¼°Êm9Œaß«l¢=,ƒšÎÐF²qa tŠLØkº ê5,[ÓÅ!‰B¼=œjº›_¤²{º±ÖZz1 IØ[kÀM)q¿µ&]Ão±{º°Åµ ˆûî›Åt;­5oéäw‘1Õ^Ä›Ÿ}áOî8â¯Ö…„%|¢¨z[âzÇaáüêwǤj„k¾qoÂ0Åc¼h,œóbŸÂ½YØ× °= +ðÅß)»ê³Àþ¦0…)¼~P˜Â¦0…)La S˜Â¦0…)La S˜Â¦0…)Œõâþ~@¸âóW[-~úñ€°T|þÓ ¿¼·~yváScáÓž„)La S8ÿ!š’ژ¶”0…‘sˆ%wˆ LM}ÜFEPXM4lÂ.dZ5˜¨‰‰¦}$…£©X_X®Â¦ËùRQx±R‚Âf7y8òÛ®K –ÃlKh£¶ïé´…*…€Ûï^˜Ï%(La S˜ÂØ`\>nðùGËÃåзB®þü§>7>?½ðkcá×Ý S˜Â¦0…)La 7ïŒ;ù{Ž*,Ó;ãjMìò÷^¸ÜWkúc—¿çY…O‰nê÷PX+žUR˜Â®nú¬/¬¯¤B¸Ü$Ù²°iIXÊ?bÚ“LXL ¿¼oHXF„µ›-ûFX¢0ŠÂjê‚w…E&Ó¥…O[V ‹y5 # ‹˜¤¾W覹W »tBÌD5]¦¢Fø"Õƒ Gb¹Ñ—À3†¹pà‡!$T¯+¡Fá뚌–Ã…MäØÂ¦YFÈyúÂH>‰,Â^A5~Œš]…͹3áHÆÇ6ÜG‘A¦ÐÄÒ½$aÀ©øÂ@O(ëÃÂíÝ®°Á…ÕLÕÅ…¿ÉPX=›už)[Oج$¬N3OXzø[6¸0 õ5cü‚ž°Jª§œV´ÛXü“—ù°" WÇ®Ïj ƒL·$ ˜!mdRÏ&„H?M£p¿-!’Úᤷ% .<ÂjÚ«e¡Û–,g1ž‡ Jc8Ÿ Ë a–ÃA¸_õÊ6…Q®œ¿Éºüs •^S +6(ì™aÊ/Wqá5Ÿü¨¸°šFé°Û®°NüåÛ6í Ëa1Ýð=]Û6ÜiK¨lSXÅ& 6!œW~¸)aoôO¶-çM ³ÞŠðÆÿŽÃÛê)å›ÂÇP¸6S¸y9¼Caâ¥^xâ÷”…a{þë—?þr »kâ7MÇ¿VôªJtþ=cáßSÖ½=Žññ=„üü}ø¦éøOïøïÜãùMGO&:ÿžñHßãR¸§Û°‡š2ò[þó¯{<ßtüd¢›a;¬p9Ĥp²^Xl×ÂÈ=¡fº1aÛ“°Œ «'æÎñ£fZ8¹”p±^ݤ°£ºî\a“âÉzáa“ä7Œ6I¶),ÖW×.‡¿³t²~ǰIòíÛh“ä€Â~uñd½p¹œßœ°C¨'ÄÝ7 La¿:?ÙNXÍt7ãéC ÃXKX¦ Ë„=´—˜i£ˆ1z²°„?Ï \è ÑJXCü¬Â–Küg“¦°•…ÕwÞÏì¦0&ÇåàÂÖ@x–‚¾UÕtet Ÿ Sø•ÂnRÓQ˜ÂV3Ík*†ë޹島‡ç·k]X áüI.…ç¶ksa…´7Ët¸î…g·k]X5Ñ"ìâæv½¥ã Ûb¯w…µ/<’†çíÚYÂîõPkíã{}\¶$ìíZŸŽ$k×ζ áV±¾pÚŒ¶k«…) Ü(\ÕZóûH7IÞ®¥p›{:õ$…›<½”ÆÂ¶Õ„)ŒÉqnÒZ;¾ð_¿ÔÑð¡ïéä^}k’‡…·݌)Œyqq…2…çg }£p¡¦«>7¦ðë×SXᣠ·¶'NÆ®¦p× bzoAa§£pPòÐòQ_-ô΂ÂO(l÷…e@¯…!.l¦qcù‚ÂNÇöp€ë-$‰iÅ!. t¥„ #¶þBâ)}èlLEÒ”•]Øì®0…£”šk 1ðò#ðß[P˜íáqaEØÜ .Ü«¡¦÷v: ;¤/qšåa —(n°CÚ–˜+ïéòÁpÝ‘Xy‰¹r°=œ †S5‚0PZb®ÎéšÚÔ%æÊAál0\PGwVXb®lçƒá¤[§6ì`…%æ AᙡëÝÓáëâþ^OXÖû²øéÇzÂöÂ/ïn§í SØ6"La SXö$LaÖtèOò¤Ú Þ0…Õ…ÕПäÉg §·)Œš8¹ðíÊ»IØ}·&œŒ©'Ó^ë΀Nx›¥DíZô—uòpoçyضYJ4ˆÆÂÿÛDÙ^9l;ö¶„Å]8†A+%(lj-ƒÂ ?¦0Ÿ^M˜Â¦0…±¸ÌÆã¼z®~dÏ$¶¿¿m\ø5Â1’¤³¨¨—ÙpÌÀÃ%½;a£ðMÊP /¬2^J¸pz§t;E¥°V8¨¨k:±)ÂÁ¤ÛY&Láè$…µ'Œ¬¦CìwòÎæ-YDXû¢»`*bƒ¸0ìFØXÑ--vƒ‰ºLETFáÒ}šÛ"Ä—ÞÓ‰L‹ÿÍbÚ FÏù«…Å‹œ^Z&üŠÕ„æ`N*÷=’°aMa… §Ajr8a“…óyÕL'¬²¢°JÚuÚG6Å ›—"¾ƒ³”¨®éxOW¶ç¦0…ùô…8Wöªzyváÿã,ä” ñkçÆ¯?ž\ø?ÿúž…üœ ñkçÆŸö Äc™‘2ÚôõyxýÐ7 · =/#,fÒR˜³ˆ™6¦°Z[a KØìV˜Âœ_B}»Ka S1d«ôn+<šÇ¥NXÖè;¼†pÅmæî„_Þ÷%|~LØÖ>íLø•¦p9(\_ÓÉCú“ì*àpÈd®0…ÕtxhâšÒPXUMM`brhaµ¸ª¯ivw%„»dO#Üý´SÒî­ó±€°Q{aS5Žx|G…)Œ¡p¾ÎGµ°=¡°Š › „óu>FÈ{há/‡{ãM²u>–NË2]Ø bð¶Ò"Ôi7¾ÎÇ’÷tÆM¬~O×nôïšÛ…)\ S˜ÂØP\ø¾mè…Û†žKÂ3æ¦ðøO©_Pß SøÌ¶Dcá×Å{U Âöqt•K5å®Gçq)S¸:¶/Lá©~çô´¥°õ•'vø•imQÛ7›Â/ï…Ïq7·o6…OS…_ Â/ïm…)|z&a9¤0…)¬O…Ø”°šè΄M?6“)²^F ?®ð×F8uƒÜÀHVí­xëNdÂyÖŠ-„¥×¥V‡0ˆ¯zïÚ¬£W_8ÐKک鮄_ÞµÖ\_ÅäF×rX-ºFZ_` <˜²to§†Âb”Uô…µ{Õ\ˆy÷„#¾˜‰¸0…“ ¾QeDX§Éˆ0„¦p°Q5Daqáob™°—ãÂfþÂs ˨0 †Ø‡±ðx[b¼FL¯),éSDÍÙ!¹Þ²ÂÁ ª¥w@¬xÝx[BMeea˜fÂ…åè¾úÉä‘»fçÙ‚0D¡]#^'.G×^ØËáG„§YSXDnfºGa9º¯~WÙÌ“â|_ØëåÂrt+›nC¸Üïá÷·qa`(œ/G·²°aÂå~—qa³L8[Žn]aÃ6„Ë‘ kTua–£[GØd²0fÇ¥µ°¥†~jK”–£ÛÙßÓ•Cß–®GwDás»R¦°ŠMîøMáù¡fZèø]+LaÓBÇïZa  ¿k…)l(tü®fk …Žßó…)œºÃ4¤ ¿ë„‹ÆeÂÙ›ÐôžN,u¾3aØž„Ïû†íJøuwÂjn|OW¦pEM¬¸ Lay¼&Vk/<>NN!Ù[ kÐíBøüÅOwœœ˜ÞzRv(ì@²Žp>NNMB_35¾…‹ãäbÖ_dN¦¯AGáÏÇÉ)¤?õ‚§¥°Ý.…Qˆ—já|œÜ@Õ_¤°Ý Âz¥Rß8_ºä¾pÞ¡[NYÇjá|œœ k/]Xƒna1Ôçºåç¬ãGp>N®F:¾¦ kЭ&ì5´¨ÝÖÇ")XÊ7š¿P+œ“Sˆ…3i‡˜ÖÂtë«ör†¤´ŸôJy៿¯.¬. ÀìæœM'j,¬] wõ±";7UX {ìQ8 eç’°”„õ–…Â&^k¿ÖÁTYøngd { -Þ–ˆ~ŽÂ«ÝÓy¸ˆîV˜ÂF yT˜ÂV¾A¡0…)ŒEãLaOÆÉU¬A·‹š®½paœ\Ýt^;(ìAa cNœç Sø¯_æÔÄó…)üñpM\¦pETS¸å]zïÂÝ{ˆâ:,%¤õ¶DàGºØÛs…‡¥>±l$öÎ…mé˜/ K ¸pH×ÔtV/õ½”pa³ a ÉA©/v;›€V SXaƒR_Ò¡t;HA˜Â{¼§£pûy~(låy~òžÖÎE‰f?À“¢›þ(.ð´ª°¹°d ›.ÇZÂbb"YwÏ&inAƒA¦im ™OK8G˜Âj½§kš}^ ‰Â¸¾,&k Ëž„UµƒŒ‰v0[”iLFa{X˜Â >¦pÚ8ø]a™  Ç?W=/hûå°™T––`¦7ÝÜ‚0…õ…}ZÂzaLŒó®…+®«þ÷?*f 8š°ZáÉs \ž@ØWÄÞ…)La©š‚ç_P³=(üñ}ù¸Ì59¢pû`¦0…ç…)La S˜5…)La S˜Â(ÄK0…§MfRž4™IEP¸}Pxý ð1k: S˜Â¦0…)ÌÖ…)Œ ÅùxÂU}¸ôý:žð‚}¸~^¢ï×ñ„·Ö'—¦pƒ 0…)Ü6(La o5(ÌšŽÂ¦0…)Œ Æù Æ÷žŒÞ¿ðÇ÷íÅå ÂŽ#S˜Ân/Aa S˜Â¦0…ù\¢nzy>[«Ÿ~P¸m¼¼S¸mœ(<'dƒÂ¦0…)La «Š)LÕ Søºž¥„-653I;mIa…¨Ä€ÂNY7$¬‰0Ëauê5Û’J …-,Lá Q S˜÷t¦0ŸÀS˜ÂØh\˜‡Û†¾Q¸my©çÆÂ~¥0…)¼^P˜ÂkÆ\/ Ïëï;˜Â2§¿¯¶”¥ðË»JËâ™Â§ob-…) ±¶Â~76¾©– p…"…»•ËárPXG~‡˜æÂïú81…!&&ª‹iÍ:ŸÞnSøÚoMÔ$¤ý8%‚°áA5–äiÔä¦cqžILaß „€ï‹áÂüd ë­ptÌ:áš °¦]DÍ:W ³=Œ®#qL‹YÖ±¸©0ïé/La S˜Â¦0€ii,Ì<¼Ka S˜Â¬é(Ì^U/³…)\X2â4<üõÇ#^þ˜¼BðŸÏ­é(\%Ea S˜ÂFa s\3…›…מeÿøÂ²ÎйŸ~P¸mkíå½­0…OG¦0…)l SXv"Lá<(¬ª¦&0iÄLaQSƒI&¼ 8…½Ÿ»Zca ï¶µFa Ã`bÒH˜Â5µ¦pAfAa «µ¦0ïé(̧—«S˜ÂØX\˜‡ÛöùÑ·ÆÂ>?°F)ýjá×çv&Ù­0…)¬qÓ:(Ü,(lþ´ «‰¶'¥p»šŽÂ&"»¦0…ÖV˜Âº0…ç,ÞÙb”Ìñ…eÆâÒj” …ÏUÂåQ2~]Lø´ua SX¾\˜ÂÖÄ®QøDX¦pÂUK[i La1Q5½.2# ‹‰p8›v&&3„),š„Óè™.áÂéÂîE™.Ìr8qŠ(`‰Ü,œV3øô‚ÂÌ…ãeAÞ¸‚°b†0…M†Â¾ì‰Ù°çì™ÂVÑ`…ÑC-‡ÃÕ2Ý€5ЍJ6¨‰um mKˆÜ`ª ïétÂ=_6_˜Â2EX!.}a>— 0…)Ì'ðFøPxµê»GÉP¸ò0Œž' SXq] œòE÷)Œ)q~T˜ÂãËÊàæø÷·LxÚè /+ó ·g.™ðľó EF¹¨0…ñ¸ðÄB‚Âh)La  GÍ„«ûÎS¸k²¸0…áÂwòðÜA嫞OIXuLXf*âUO%¬.ìQ. *âUÏ', Ÿ& ŸžKؾB˜ÂFá¯h«I#a g$™0po"ÑÎFz·cžZØ&«™|&l¹°™¿Â6E¢°°QK h° /¸p>–Á&&O)¬“„˜÷Œ‰TJhðtá|,Cä¶ç›Z'Xï´íÂcåpw‰<¹°•…#¢B|ØAJt¸¡p>–!SøÓšNÂ&êÅ„ ”Y6-SXï—™p6–¥D±QQX4K ( bÃ@x8–Ø– p‹{:mxOGáü˜Â|.Aa S¸çZþ÷™5ÂÎç\Ëÿ>³N˜ÂåXVX žÖ#¶N˜Âå±m…)üòÞV˜Â§ S˜Â¶²0…)\žëg a «™´¦py®ŸºšŽÂå¹~*„)\žë§N˜Â…¹~ª…)\šëgia kƒR‚ÂŹ~ØZã=…)La>½¤0…)Láõ‚¦0[kf¯ª—*a ç=b‘õˆ­¦ðGažŸ?+{R¸<ÏÏ¢ÂFsa £¥0…µ½0…! …) n6R†Âh'Laý a G¸ÓVÂ,‡Õ4Š/_ÓQØ\ØÔZ³=ìÂ"‹ SX\xùö0…­½0…­©0…Õ…Û´‡)Üi@Læ#S˜3xP˜Â¬é(Lám…)La ³µÆùÖZ s¾µ¶ÂÞyïVŽ2 0…)La û:2} \ 3‹e¶°0…!&–æ[‹yXaXlF; «© ¦Y‹i[T˜ÂU¯Â¶¬0…!¸°"¸¿™/ÌR®ÂÖ¨”`9lËa¶%L @,%d¿Â›Oa S˜Â¦0…)La S˜Â¦0ç[£pyâ:a —W ®¦pEP˜Â^'(La S˜Â¦0…)La4Œ3…ýiO‹øýÂþ´§I\(Ü:(¼xP˜Â¦0…±±8K¸¢}Û¬M|8áïÛŠËÁ„7¦0…¿((La S˜Â¦06çÃûóÆîœ#üñ}›q9€ðƃ¦0…)La o3(La S˜Â¦0…)La ·Æÿ⛫•qT)IEND®B`‚yard-0.9.12/docs/images/parser-class-diagram.png0000755000004100000410000002602713206751010021503 0ustar www-datawww-data‰PNG  IHDR­%n:˜êPLTEÿÿÿe›9޶µÿÚ¶Ž9999Ú¶fµ¶f8yy9¶ÚŽfŽŽ›fÚŽ9ÿÿÚŽÚÿf¶ÿ9ŽÚ¶fÿ¶ff¶ÿÚŽÚÿÿf99ŽŽ9ÿÿ¶¶ÿÿŽ99ff99Žffff9Ž9ff99fÀÀÀf9Ùÿ¶9ŽŽŽ9f9f9f¶ŽÚ¶99‚f¶f9f99µÿ¶ÙÚŽŽŽfµÚŽ8eVºŽ99fŽ99fff8yyff9Ù¶Ù¶f99ŽfÚÿÚŽ¶Ž¶ÿ¶ŽŽ¶ŽŽ9e‚9ffÙÿÚ¶ffºŽ9lfÕ*èIDATx^ì݇z£¸Æqn@t×’>½lï{zo÷;G/‘Yâñ®‘üßg2ÎÎìo_Db=ɉBˆ‰è Ç‚VBÐJÐúêÕ+´´®&vYÙßÖ/ò$™Þ›ùF/ Ðj9¨V‚Öégy2}¹I’úºLšWIºœù¦õ¸ºvyH+!¦éW+ë4»øx3“VkS/®Ûv5[¾“µ¿ÿüz¾©™{Òvá[N­• uýâoW3³*º}kèM]»ï†mƒ·|[$ëËM’N¬öÒ-\Ë©µ´&©qÐÒ2©'º>]ÎÄ6»Ö­ËXÇÔn•d·PËéµ´ê,o5Î=ºza>Ô·úTÚÍ ^X©wÆØåù´´NÝÕ@Uø×é|#žõrÖÑjmáªÖo__ú—çÓJКßDýì$é ´KwùjNªÿªJ·8›V‚Öì]sâÿÁ£›Þ–÷ªaLÀ'5æýë¯V÷c‹œ¾•p/kT!h%­­h%h%ÄŒ!„Œ¦ÔŸg«• •´¢¡&´´‚V‚Öç‚VBÐJÐJZ A+A+!h%­­„ •´´šñ„Çt¡•yâA+A+Z Z™tƒ • ­­hE+Z ZÑJЊÖ'vç­ñ‡‘æ'ª­hE+ZÑZ›r{uú!i³§YO‘-ŸV´ÊÞÙµVEXôµ®ï&=jN½Ëf!­¶%]ä'ÑŠV´f+cŠv‘úž±6ÿ¾µ ¿V¸ Ë7w¾]ä~kÓ–¾ùÆ8É©[­µÞ¨}=öøÑµ¢µö½{³¾ÓoÔZõ™o´p~Mªù¦6ËYj G¯Zä¶µÛÃV»î@º…‡»œi!­níªw° ·öˆZѪ¾![íý{ÕÙ±Zä#ת³¶ú׺ÈkS6Oˆõ­“­­Åö‚[Õ"\·jW½ƒ}wmd­hÕÒø¿áÒw&þ4èÏíu,¥ÎxÍÛ§=5¬ouºªÆcÓƒºÖ{­ÚšJëξÕb×®z‡ÔÈð£iE«NŒ¥út‘K«? êü§“Z«ÕŸñ´G8íµM£»nMº(½;Kó^k»5hM¸nõ[´«ÞÁ­í Zé\Í|ã¤:|µ 4u&ÓI­½Ðï¾ëéì1¾1oÓõ­Ë™þ±Ö[ZµÕ®;•»Ç,víªwp­{Å¢õ¤V_ڜ췵êü§“Zó)«ðB+iížöF¢µßÏ^›¢¨›óweæ_9­ÚêÏûß¼yx¼uÒîªwøUŸ]ÑzPjS|ºoÕiP«÷ž»§½Sj¥N­ÒæNo'náÏw²¨óŸNj²¸}rLº§½“kE+}keÂ'·6ÿ´êü§“šo §N¿Ú=í¡­ÜËBëpA+ZÑŠV´¢­hE+ZÑ: •¾uÜËB+uhEëh‚V´¢­hE+ZÑŠV´VEv‘g+ó{ÝÊÚQµ:¸V´¢U÷PCÅßΪÕƒVê4>êòÝ÷fñƒï[wW­´¢U(ÓÒ‰ô¿TµcߊVê[ÕªZwT­F£­\ ,¿nµî¯Z¿Ö1­áCVè[wT­F •¾•1éÕÌþ ZwW­´¢5|È ZwW­´¢uo¤5äÉjÕÝ‘0ÒÎ2M´ÒIZþáÎËþètÙµväZûU«OV«.Ü•hoe'§ýéÝyÙ—´Œ«o@+uûÆD®þbLaU}ugæßZ[~Bõ­•1f¢;'þDÓ"ä¥ÿò3…ø+)µû؆î}#½vñ1em¿ônúoC+Z?uwäÖ¾ìŒ<߯ø>XwN¦0EˆŽÑÜ!–áZš=}zw^ôôþÙʵL’°Ý]œ ­ûîŽh¡oZ+~¿vB«™{©í®UZµS‡üB«Ze[Ç»îËnÔöî¥Z{áJ ¯U‚hÅÕÛ/jŠNŸÑ¶öKÚ=¡U­Òª÷ßÒªíhEëþ»#"laÝy’pÔ!;úV½{W«Z¥Uï¿¥UÛѺog€i\‡ÔÚ¿;ÒתÉ>š•ÆOUŠèö!ºMç^k¶ò›ö_hí^åêý·´j;×­ûFp˜Æup­ý»#Zd+7&&ñÃzDø"LÆÜ®oU$Üì¦éßy‘V½Ъ£Ø{Ýöf¸i\ã¯8|¼õ¿=vŒ·_ßÓ4®ñk§ýÉþqô?´öGpâÆµ¯•:®âžÆ­h #8±NãŠV´öGp"ŸÆ­h #8±OãŠV´0k´õ­±kEëÓ¸Æ[ßIÐJÀñwG ZG˜£´w­„¾õл#h h=ðîZZ¹;2@ЊÖÃu€ õÀ»#hã9¯{‡nƯõøñæ(´¢5ö¡›`­Ô·Æ;tÓ·G}kÜC7ÁZÑûÐ ZÑûÐ ZÑùÐ ZÑ:àÐMüó·>T쪭hEkõ­]­1­Ô ôŸn7ß4•¬þ1¢ËYgªÕkE+ó·ª"Àjµ/ºS­v'pEë™îÖÊü­*ÅÊ.~,;“~ô'pEë©c\>©•ù[uðöf¶=éGW´ž8FÙ¥•ù[Cßš§e»Ù1íOàŠÖÓ[UÖª¡-žV}k÷ºÕÉ “~ô'pEë9¬*Çi}šõ­ÙjkLÀ “~ô'p}vZ‡ÌAõ­¾Ñ5}kwù¶}^ßëý—9u<‹ðD}ë!õ­jÔ.~QÞW,ЊÖÓx=¨¾UÝ Ï5ì£ÃÑŠÖÇæz`}«ûZí¸ZÑz¯‡×·ª‘¾­ç‰9¢¾U}­\·¢5¾úV5êÙx}k·žÕLÒù¶ÖîvÝHQ㨴¢U÷Z¸¾5éÔ³&©1o/;ZÃvÝH ±heþÖ0<ã×?·»\½Ñ!¡Vÿ³»G¨YÏ„ÿ—{µ=L¤’Y ÓNZ¿Õµ„Þ±.“ºÔ!ÚAyp@G»¬/ÿî‹»ÃDú>á@µ£­Íߪ–r}3û"×!ÝØtÚ]RS:•á-µÖ=PíhEë¡ó·vµfof:¤[ûà€ŽvqÕ]^eg˜Hß'x6­# ZU}kWk’^—í!òþɾU»T×þŒß&Ò÷9sߪ¼:EŒý¦§ cûë[·øhÒî6öh[®þz‘‡¤Rß'´§­Ô·nóqc6Ù»ÑÛ”û:~—lUXŒÿ±Gw†‰ô}Âc×jô]cÑJ}ëôƒMÀùbô5HÐÚ¯qM¹´ö6î8âùh5"K¨@+ZÑú˜X—+A+ZÑŠÖã'Å#h¥xÒZ5ä©WCÿè6ZѺ/1jE+u¾Uu§š‹ÕÓl­ýB>¾ ­‡­·E[†ª9­¬ÖPzÚ«r=º ­‡†úV/Ru§š/°SzÚ¯r=¾ ö •¾UZUwª¹X;¥§½*×ã bÑzLЪ×ê[{¥§2­]‹VrX \Õö3v”ž>ZA,Z ZU©ª¹XCéiÖ)I}¼‚X´’ã{áíg¨‚X´sÀ\¬¡fõÄ¢•P'£V‚V´¢­hE+Z ZÑÊxkx¸É±5h h)hU¨5¬Nk¶ê?Ч2ÆLTš:XЊÖîüUVkõУxcµ´RßÚ™0»øÑ6ôÅ“¤eÛ:¨V´Ò·z’º x{3KÖýGñ\Ý·¬­h }kž–ýGñØfÙ&hE«Ò½nu`µ´¦e˜ˆuP­hEk¶Úp@U¥ÚjýêÎØ”MëA+ZãZ Z´¢­­hE+ZÑŠV´´¢­Uu­ ZCЪ)¢Z©Ð.Ë7{fe8hE«O=IÒr߬¬1hE+õ­ŽjUì•5"­håJ`Ϭ¬ÃkE+Zõ!kשּׁ1hE+õ­W3ûkשּׁƒkE+Zõ!kÿ¬¬C­híÏÊoЊV´¢•:´´¢­hE+ZÑJЊVê[cŸÆ­!Ô·F>+ZC¨jùîû¸§qEkõ­±OãŠÖê[£ŸÆ­!Ô·~÷4®h ¡¾5’i\ã×j>™³h¥¾5–i\ã×:xßJ}k|Ó¸¢•P'€V´¢­hE+1#ÌsÖJ^-hE+ZÑŠV´‚V‚V´´‚V‚V´´‚V‚V´´‚ÖÃBÐzHÈ:ÐOø/E+ЊV´´¢­@+ZÑú|ƒV´¢hE+ZÑŠV´¢hE+ZÑŠ´¢hE«9&h=oÐzô±hE+ZÑŠV´>àUj´>´¢­hÞ›­@WZc Z_:¨ér†Öq­z ¤_©®)œÙéZ# }ë½Vÿ².“ºDkŒáºu9KýZß̾ÈÑ_è[ëEžÜkuH«"»øx3Ck|Ak’Î7Û}k¶*’ôºLÐaК­&ÉúEîÕV“îg9Zã c·e’óöÒ ¸ ƒìÝ­# uÓ ZÇ´¦‹­±­Ô  ­hE+ZÑŠÖ§BßÊ|£É³ÕŠV´¢­hE+Z%­h:hE+ZÑŠV´¢­hE+Zãzæ.ZÑO‰Ö'´¢­hE+ZC¿V´¢­h­Œ1E²¾36eÄZÑŠÖlµœ%é"_ßM,ÜE¯V´¢µ6…_z­úÁ~SÚÕ?ß.r÷ºpÍf‘«i8­hEk*€­V7KJ5߬ïæ·êº[·PÓ}+ZÑZ‰`¸¨YäÂ;ßtm ׇVžìEßjl /´’V×Ì7©q)#ÒÊÓg¸n•^] ˆfj ŽC+ZçyÿR}kmJ§ÙöRÓ@ZÑŠVqÕxëä~õÚáJ lÅøúVæé N­hEkü3Í¢­h=AЊVôÍ7~ñþËÜ?“¦ðk‹\ùŠF+ZÑZ•I:ñ‹z‘¯_änƒ{®G½ü“m*Ç¡•ŸËzZÏõåÆþJ²‹Ü6¸µf›ò…VúÖ8´ê–ß"Ÿ^Í­•»ÙçÖ’DùŠF+ZÑzÙ.œÖõ]á6h›ò‘V´rÝZ/gºnÕ£½²•Gk_¡­ñ<‘vÒ|üOÜâ§‹Ü¿]¨1{·‰R+Z©PoÛ}ÈWdZÑŠVUS,ò^í%ZÑJÀH‚V´¢­hE+?—EÐÊL³£ ZÑmЊV´¢­gu€V´´¢­hE+ZÑŠV´¢­ÿgï v†a0\×t$m:hÇeâ€8pCBBˆÓÞÿ˜¿«GrÈiª2ï¹Vdÿé>Yî¡58¨ø½¬ËOöªA©YÓ¯þÚº’J¹~¥ë¯Õ—¦UiUZ•V¥UiUZU©Y볕Һ~¥J«Ò:„³9^=LñõywJ¥‚³wÞàf~ÁÌ’èÎä\ã¶T©Òê0!Ã&{\©R#2o&|}_äËÿ¤¦tŸttáöçý¾X©ÒJŒÚÞð¤Þ‚q4’n·w¥3¾*U*iÅ{¸ã–D3fã¥Eª!ö¼.µ•ÕÄ ¢ÙhÜL¾‰ú¾gݧƒ%J•VªJ3ü‡Ø–,[6ã«Z¥Fôu Ø B‡'ž!Œ¿(ÅK'5ä@ç=C 3=Xæñ`ZµoµÍ‰Ç|ò-,šñU¯R#S3K¾ £Nè@{N+ÔÀ††MÂÛòθ (þ§Tk+•…¾q›Éw¾lÆW½J¥‚ˆŠ,h…'K+Ô$µ5¶2^Њ|°T©v½ñ²bʼnHŸ®lÆW½J¥”g™­ðdi…8зòf³`Ì RðÁR¥Jëfâön·GÆÏÇ¥hÆW­J¡QB&@`A+C¨­ÔÖ¥´¢­hE+ZÈû׊V´¢ÕÑŠV´š¹? hE+ZT³;׊V´Ú=kE+ZÍŽ§éhE+ŸdàurÐJmE+Ï­¥¡­ôè`Ý"h¥ßŠVö²ÐŠVΠ­hE+ZÑŠV´¢•sYœË¢¶R[©­hE+ZÑŠV´¢­hE+ZÑŠV´¢­hE+ZÑŠV´¢­hE+ZÑŠV´¢­hE+ZÑŠV´¢­hE+ZÑŠV´¢­œËâ\粦ÿöS)º4sÝéôÌö›zDnBÞ§V´¢­eh€õ,W´^ݾ-v§éÇ”IÐzql+´šZ‡A+ZÑj“\¡Õú 5­hE«M‚…V‹A+µõÆ¡¶¢­h¥'@O€Ý´N ZÙËb/ ­/Æ„ ­S¸~‡V´¢­W5…ÖSChE+ZÑŠV´¢­hE+ZÑŠV´¢­hE+ZÑŠV´¢­hE+ZÑŠV´¢­hµ{Ê…Zm©,­­ ~ª¬%[ÑŠV´¢­hEëùÚpÏZeàÝkE+ZÑŠÖUmJµ÷Ó²-ÆŸvl-ïWÊϧʶڣõ¦AkTx^ëë O8{þ²FëLAkÙÚúӺÑk˜}k­ÖÖÌÌòUÝcr?øPïÄø¹}øG—µÞY¬êjÿøT õªA«Dfk§µlsöДmõo}h¢Ö€¹[M³Cjrž·Ò_Ê/ký nQÈÑzÍ 5S)Õuág=Îc­Î° w…8•R.Ʊ›ôKñÛµÚIX+ZŬl»r™™RŒ´º¿úú¨¶úïø»V¹vUxUï6nöF­óˆH_+µµúÑŠ¾j޵ºd–‡…øÜêGƺH¿ »×¿ ´^7h-Û„Ÿz‰³¨uk…^N{ëâ'Ý󄻤©­ãÖdù¹[ޏ(#‹õôwkfy¬­æRôO…#jG÷·ªÝTà£VUÝ_-w“j§Ze­g2nMª•®á3»Ö™"º‰jEklMZ—_ÛO;iõõM_9ü}hü,q­™Šp¢ZÑ[“±ué†üÜ8­±ç©–eh¥­UIU+Zck2¶.7+S_^5ÓÐó\J+ZÑ[“±u)¡å/½V7w/"zžKiE+Zck2¶.}[óÓ µõ†=…’’V´ÆÖdl]†–‘Ú›'Ï­šQ[—ÒŠÖØš´.ÿl ·>ê øž'ZÑÊ^ÖMƒV´¢5|»‰G4<—ñ{Ð:OÐZ¶Å*þ¼­¢áÛ¶ÓÐ:[Ðê®þèB8› ¡ÜßÚ·Öªjú >„÷̬­h}|²"Ëp6!´T4Üv„wŽ>Ä už U5óÐHk8›ÐoV~šQÓáчŴ¢•ž@æ‰ú³ A«)Å@kXA+Z'eÂç"†„•°á×]Zà ZѺàýecGThý0lú ´†´¢uÉûÛü¿ÿ÷ƒ?› aã»°­ÇGº÷ ­ ÞZ¯´¢­hEë­h¥¶^´¢­hE+ZѺÉW?­Ëßš×¶bª¯ýɬM®¹.ßזϪçj´*ÿ±wvËmG†“*ç $2¤d%&ú±åØ’9‰ç"J*‰ßÿ}ÜÓ<¬Áx¸Õà³;‚¾.p»Ë •ê«ævŸ3=†êçO¶Ã´šöâÏNÌ1´±ÓÓt0Íe2ZÉ­Ðj„îŒñÿî¯Ëߘ˜rõêÉ͆á^·Û‚V;^\]ž>þw:¬¦¦Z¡U8žl‹ç&nÒвó$þ™pýû_æV#üógï¿ÜÚy2Z¡ZÏó¤ ÿ«nDˆ—oÌu±öwƒ?®Ï¢õZ»¨Øƒ‹¯ŒS;ÌE+´ò&`•Ôóíéã?=»4L‰>Sòá*çÖs¿8YŸ¬-àÓÓ ­Ðª"+é”Ѫ[E•åÓ°ÒÅ›•­È´´Îг@°ÊÉ>N¤-òEçöGÿlã§Lë©oØóö*½ü°Vr+´ªÈò‘,§_n-·þS=?eZÝ|éÈ.Îì05­Ð ­õÐ+¯ª~k³Ò ­ÐªÝ¤jZ«µí*Π5G¤Ú…ŸC¹pàÿZ›´ªN­iåBã¼ ­Ð ­‘>¸uM0ÑêC›ýââê_K7[,ï ›Ñ ­Ðéƒê­­öÅBM¿uaЮ&Ë­Ð ­¡>hHZ)pú8mp(Ðnû#U¥\ØŒVh…Ö@42õðų˅BѪIm¥\¸­ø[T„fWhÍEV‘[W–nõø–V 0Y.Ü‹Vü­{Й]¡µÖó{«}t!Zí[-îE+®ùZÝoeެ^ªœUëß³+´Öú`î $ ] t2äº'p½Ù‡Vü­òµZ!à$^¯‹ ÖB³+ZV)îC+þVùZű!YV°vjbve]V)î§eñ&`l:tþ÷Éi-*Xûf׆´*^Œ GnttèÀß*_kJ±bS8gZ³ëT´B+þVùZesM§²‚µO`ví•ÖeŠ£¢«|­iÊøë—kG²¨`S}˜]›Ó:~ºõa,õF+Z–tÀ¸z­£oZU,5¢u٭Л]?NZ—KûÜGŒ%˜A×k¯´âh±ËEZ—B6ÐGÐZ;³ u|@«(Õ·»õÁËíêVÎúKÚuÈ~v¿.*ÁpÈõzü´Bë2ǯKk‰¿±YëƒFí:É€² MwÞ™ßõɯZ­™~÷í*îz¼ZÖ"ê·J\=;i­Ãa×+´fé5e#Q‰À«ÙW^ŸÊïzsò§þKsàwí„ÖEX[hY±ëU<âouxQ°Ž ô-«ùdxÛP)$Ÿ|˜ëŒ¹Z¡µÖõcD¡s­¬óÒ ­¼ ¼Y‰ÖB"ôa®ñÜVh®_­(ýÑU€ƒÍ«Ðª"+hhÖ¹Õ‡¹s[¡5ÞÄŽ£Í«ÐZ냎£} ‰ð·¾às[¡µÞäáß<·ª| Ì«3Òºœ"ÆÐZëƒgOÝT÷ü^<·Z‡÷±O^…˜W'¦µejÙjn+´Öõk¦U«0G˜W¡µÑÜÖšLü­¢U«0ó*´ÎçÀßšs«îæÕc¦U tK+þVÑšË×À¼:­ÐŠ¿5Ó*këó*´6 hm0¬Z´6Ö ­Ò¥ äek…Ö¶­Y,b”­Z´uó€›Z#œVh…ÖXÔ€›J#$·BkÎl’‰ –Æ´ÆúàbP#„Vrë¹j—ihõÁÅF8’Væ·F»^;£Us‘ÜߔκúÿõrÓ–ÖZ\ i„#ie~k±ëµ3Z}wÅ“‡+£5MHthØKägïmìdZ‡õÁ!p$­ÌoÕ^"ÚcD³Yll«6Õ\¯ýÑj¤.Õß<ÚøUº-hÛÒZ냃á(Zñ·j/‘rVsJJÚ˜$r½öI«å×TО'7%P;Z›ÙZ¡µ®_5«5/ Rfš¡ëµãÜúÙ§Ë_YÌOklkiåM@Uˆ/Î,hõuš‘ëµ?Z LoŸé”¯>lŸþVÍjÌ­±ëµãž€ýx7tÝ0·Nâ«öQåjÀŽN«6& \¯SÒŠ‹ù­g»=T”|![†×²‘ëµZ¡-+v½öD+´Bkìz=fZ¡Ÿ´B+´B+´B+´B+´B+´B+þÖÃm°Ñ ­ø[·ÁND+´âoUøý‹kÞóŠÎ×oGØ`ûœßz ´âoUØ}÷+:Ý–Ù`É­ÓÑŠ¿ÕÃï‰ør[íÐ;­ÐŠ¿5Ó*Ì-×WedƒŒVhÅߪÐ2#w–¹5²Á6 U å{….ƒ‘SGN+þÖŒ‚ÿ|}˵Þ[Ãá¯ãi:5­ÑX”ã§«Pð_yýr½³¢óûÇ¡ v$­ñ>j7ÿn?x¥÷¿t90r ZѲÄplƒ=œÖº£!½#aÏþódû±çVhU•ïÙ³ò·êvlƒ=œÖº£a‘GMYÖߨe4rŠuYqàhó&°;jÊ^§ÓeÙ™hI«âEëø i…Ö\d펚:{ê– h% µîh¨Ž’wõÞ;ÆegZghÍE–)KÃTü“]#§BZûþi…Ö¶#§ú§«d©#¢µ9u$´âo­Qeí@'­ñþ#û»Y¡µm@k¼ÿÈþnVhmÐï?²¿›Zg ÞDã=ݬÐÚ> 5Þ$v³ŽˆVþÖ R vZí˜Vh÷ÙßÍ:"šù[ã¬YýÓŠ¿µ¤õ^nÖ^\-ÃM`§Õã§-k´–ÐÎß:ÜÔÐM?cn…ÖØÍ:.Úø[£¦†:ö ²½BkûÀß:ÜÔÐM­ç-m¯ÝÓ ­ůåo šun•íZ§ü­AS#ØiZ' ü­ASC7ëžÀõZ§ h=|_šVæ·*I¹ïªZã¦F`{ýie~«huµõëþÖî‚©m®KݤSÑz®n$´öø[5¦õ•l¬þQâ…Ö«]cÑš”õ +]ú ü­Þµ”U´zÂ…Öþ«réî*Ý ¢«T€ƒ ®ýÓŠ¿UcZßÉÆÚ`¹vk«h=ÜàÚ?­ø[¥þÈÆ*Z ã~h;Ïÿ‘:jløRÝWh=<Ð²âŽÆŸ¯o{kCšÀàJnmÐw4äÍú\¡µA@kÐÑÈ´æõ¹# ®ÐÚ6˜ßZæÖÜØØÇà ­Z㎆0ÕúÜWhmÐZw4enlŒ0¸Bkƒ€Ö×i…ÖX Êꀴ׾hm`pí˜VhÕ .hÅ'­±¤Üj·LØrMÈU iBsÓ:AtC+´ÆjP¢U%ôr4!Í>‘&Dní!ð·æ6º¤ƒ8ÝÓì=†ÖkI«syæ´jö ´öø[ƒÜ*´¡µ·Àß*ZõÞê´J‚ÖŽk‘[`iBzJnÝ3 - Z¡Z¡Z¡Z¡Z¡Z¡Z¡Z¡Zñ·Ö!1KrAí]Cë ¿u˜Ö)(ï ­só[K« ®Ï¿µ»&Ê–O5ÞZg ü­—òìÌ6Yî¼ O•—¡u¦Àߪ÷yý}ñÞZ>ÕxWh1ð·Z¾L§ÂàªOñTï´Ð:uào•[íÀº¬Ùë¶ð±¼·êé,ê€âEóèŸVü­ªúÅc6¸ž>òž@ñÔA‡Öæ­ Z¡Z hmÐ ­ÐJ@+´B+´B+´B+¿ÕØ i* UM÷zû™½sYa¢h`Ì«&1Ï‚y}@ d×ÿÿ§‚LA°‚«"Ì\ܹ=ˆ‹Ã½?i ‡¤ßŠ<úhý¿?²†…CÑj9NP×Ò›®Ö'¶Úo«³ç­’~+"©3s!¤ó°œW!£¡•CÕo5ç»(åЊv6¹Fäæqú­Öλ•úhÅ&×{wûGP|Á/¾ÍNv³of»›ÐT ¡"¢©R‘jüÿÿï}ÚÙEf œ'ò;Ì&7—~<ÜNÂá¹leë¸}k(Y¨]à€­!9[Ù:^ßÚ+YM=ck4®leëh}k¯dÜé[ÛÖò埶FËV¶ê[q“[Ùêl[ÙÊV¶²•­l[ÙÊÖÿYßz. žÞšÁVè[{ÎNoÅV¨Z~éÎÊ82MT¬CkLoe+[Gè[#_-A`•3×3kœÊleë8}ký„ÇѸž \czë8¶Bß:é›–h\Ï®1½u[¡o guë`à»cÙ }kXYÕÆõCëX¶BßÚ}¦MÙka8p­Ž÷°•­:°5AàÊV¶:[SÀV¶‚­le+[ÙÊV¶BßZž'b+ô­Oçl…ªå¯÷· ·û‡¦™/ʧü›?#nId+ô­moëvY¬å¡q¹Z/6»\¶BßÚÛZVõ§:ǵYu™ÖVxèm-Ϥ¨œËVè[Û[ó­Ð·¶ûÎÍéæôM`-k"[¡o­~N›æþúôlý5Ýß ¨nmæ²l6Wk¶²U'ÀV¶²le+[ÙÊV¶²úÖ˜5˜ÑVè[Ë×ñ¬ m…ª¥Ý~üÉÁÑÅÕo1ž5§­Ð·ÖÁ¬åifå[º9m…¾õõ¼K\¾{XMcž5£­Ð·Öž5ÒÖ¾gÍj+ô­µ¾>íY³Ú }ë$ÒÖ¾gÍj+ô­ï¶úž5«­Ð·Nú´U'}ë$ƶþ»ž•­lÕ €­le+[ÙÊV¶‚­le+[ÙÊV¶ÂüÖ²ªY2Ío…¾õ¼­‰æ·BÕòãOMä­ÕÖv{µŽ1®7oꡚl~+ÌoL ØZïǸv{Éæ·BßZü­‰k»]öZ׌ó[a~k¼Ü?_·®éæ·BßÚŸ­Óùqëšo~+ô­ý{kyŽZ×dó[¡om·G¨‚ö­«ù­€­:°•­le+[ÙÊV°•­le+[ÙÊVè[óÛ }듲úÖWu„k7{u³®GâZ·M]Nºñm…¾uu;«UKY~´¿¨ýÀ»ÄuVÕ.ˈ^Ç·úÖòLÂã²7%®uYˆ¶BßZŽÏúþêæ÷ýÅñ8×ÕmYMbgt[¡o-OñqV—íþ›õQâZ¨ý`ìŒn+ô­Qv—¹L›ùÑ8×ú­~bgt[¡o}U´,š6/ïâú¡÷‰k¼Ä޳•­:°•­ÿ le+Øš‰¿Ù¥c"@`@Gý;dìÄ Ü“hÈf+¶¶zÈÀV[O²ÕVlÅV[±ÕVlÅV[±ÕVlÅV[±ÕVlÅV[±ÕVlÅV[±ÕVl½[£‘²µU.lÅV[±¾ÛŠ­`+ØŠ­`+ØŠ­`+ØŠ­`+ØŠ­`+,vé ˜Ìaÿ†~,!Ü2l[e׎i@ ˆáÿÙpðÉ­†ïím‘ZA­píÀ @0ýSËas:6î·c©ýÁIEND®B`‚yard-0.9.12/docs/images/code-objects-class-diagram.png0000755000004100000410000017312013206751010022545 0ustar www-datawww-data‰PNG  IHDR¼ŒO{öIDATxÚìÝuXTÙðK¬n¸nÙµv v®]kÇÚÝJIcwïê®H¨ˆ¢ˆ" *¨ "ÝÝÍ0]÷ûûƒt¸‹+1èû}ž}<3Ì\fï|¼¾÷ÜsÏa@¡4Ð0´ („—B!¼ á¥^ …ðR(„—B!¼”O/?À—BQøð«ÀðU‡ÎŠ‚§ÃWUàõi“TH¡(x’ÚøT…·=‡ª(Š¢‡Ó¾j¼…´k(ŠžBÂK!¼Ÿw¤²w³òwʤ £ýDx.;uµµl…•ž‰\¯VPþ ù¨žîvOˆNö½ H–ñ· ùlÂ[/¹;9²Ëí"*?çËä–5ã'ÙÊ4Áèr ~ÀûÛ\•¥´ o=$è-8øÝó€ü‡..ª¹@âƒÇ…ëjÀ•áEè~Ú×.ìKWþÐ!@Žã}?iöF7ý€üÇ÷ßHhÞ:ŒûOY •³‡–ßYqEÆ”½5åâõ¬k'æ¤ÛÛ@ê>PÿÕþÜHö*73-/L@ØŒó6³ÎgíktÍù¿î°þœö'á­Ã<þº´Ú ì‚°NþØ9–Å&O2Ú˜a"j伯ÏÑ]0þ ‰L,¦LV`® àn…—_É€pæüÞÒþ$¼u˜?”î-›ær°­nbÂjÀ[9¿à›…úúãteÍœ ç[wt;Üj…&VÞ|¦¾þ¬åìOwÈñô+. ØÐkÆ5!íOÂ[‡IUs§üû-¤µºƒ)+Oåü¢o\$bAlþ^xÒ;ÝÎÖíKðÞ–ˆE²Ö6Dxú‚t[ÁÒ%¼u˜Sóòã z=Åó^Ñ87€‹ß•Xl¸ ß‘~@ö¬ó€ÚbK5ÍÄBc5pù ô—V'ñüK‘ t8ÕŽúÌoæ†ÑVCPÀa‰É’ßxÉaÃF»rRÖèï.< ·lÕ·øbËE®_”…h&Ùšš&›3‘g c¬›‚ÔQËŽ²© ŒLØÓÞ$¼u›Ü¸1äÅæ›˜,JO’@Ÿ A|\> OKfÆ yâ8&&Ä È’âø8q"€›Pòv áUÔÃô•k}ri7Þ†˜ˆÍºoh/^ á%¼ÂK¡^ …ðR/…Bx)ÂK¡^ á¥P¯ÂDâfwO1bçXD_áý ï6|˜"dxߟh0áý°]Ó÷:·X éâC_áý ]ÓßAA>Išº7}„÷Ãð>PO’Ü›ð^ÂKx /á%¼Ÿ^·ï½u2Ýôäùóg= /áUP¼©“†½ïGÜÇÌÝ [µ[„—ð*^–ðn,^1@Æ·¸d–Þ¥(`öo¸%?—p„PÌ#¼„·^ñÆéêjh&`ÍXH÷®[£™ ¼]¦½öŠw-×[Ÿ‰JñàÝ áU€çbíÕfÈÛ¬½þ/á%¼õ‡—3ñ¤«`ÍXpwK0] ˜6YÚxÒ(B ‘Ye0}VòöcvC6#ÖÕÜ vŒá%¼õ‡÷í×É@^!ÖŒ’l­'üìivÀGŒ –Kd¢äÈë]¹s1±·®lêp,@VüÓöë7†Í"¼„·þðúªæÖŒEÄУÏf ༬ëoéˆÛ7Hýa Þ çßÐÁçŸÈïÎïº"æ«ÓÏŸ»…^Â[x“Ú½bÝ8ÜúÐ 8³ÿòn\4dKG@šR4ðM¨E{`Ñ4À ðU~0ìàáDx oýáeOÎ{yw^lÜØ®QAÝþ|Ý«cïs·ýdêËç¿ý È–¹öúå²U¯.–/Ûõ‹ÅŒ³îç†'?ÿÀi‘á%¼õØÛo‹kð¼dúoM훾@Ú]ókñ¸Zš»@Æ3 K‹gbÀ÷¢£ƒ©o™_O‚-¯&€ðÞúÄ[ë!¼„—ð^ÂKx ¯ÂãU”Áè©„—ð~(^ëüÏW.xÊÍyá÷ÂOx8G"O·lÿWE¢W^@ìñ,©äåí-$*…s°ñÂKxëo¾êëÒVÔå!Ë®¶;|µ0y'sÖzð9°Z›/» Ýk-™vÑfâ^pÖíµ˜ý¬2Þx`¬á%¼õR6¨VÜòð«kÑÐ<þL ~ï¹ ÔüpQÌ=Ük!=6 ¸5HX ï©Û‡æÇ^Â[çx“6h*/2Ôô K ìæi="&pW-€y°>úSÚ²ïm‘ÊãEcéÌnF†+Õ +á=g;d7/á­s¼²"N’ª3§H  hÛŒž[ÕGÞÜåüâZßä\nÈ~°EŠR0\K§-ær¸9òJxãà×ú á%¼õQ6”×¼Øù;¦8€#®u„?“Š-üè€\¥x6†éàbø™T” 9J‰/^Nx o½œ°)»—5'9¦ôμUÉ:vySûüE ¬æ4¹Ç¹ÝX3êó{ÔVå+ùúzç´\ÊOØÒ0{àÙáTÂKxë¯,ZP.I$Lbp¢b Ã"c! ÏŽŒGG…åGEGæ‡GEÊõ&»äÕm­nHtṗÎ0ÂKxëïNß©Ç Ê¤ï0ƒðÞ†‚· 5MZþ@œ’Î!¼„·¡à­‘^ÂKx ïgW÷MÊ: ½²võõÃ7øûÆzüÿkÎLÒ›4OÖLH.­ž˜Kx oýàžK¯8í˜þx<€ðï‚#¯ßt¯±Ýÿ¿yc±’žZâ¢eKäz1i„—ðÖÞŠQe¯Žö{½~‘;?ï‚Ê“„¬àlˆ›ÚÈzí/¤î±2Ð ý §o@ J:á%¼õƒ·bTY„éàEæíö™$mW9ù:¤•v ^ïù¦»Ö‰´6šÏq¬„׸ÚNDx o}– ªþåíÉÏŠ‡æðo$†ê@ÜÔ¼q×±' x»Và4óÑõ97Ax o}áMÖ3ÖV^l¬ã@–ÖÃÿö¨dNÉÀ *Á›Ühµ±I?]ÙÆn+ïË+áb³lt1á%¼õ†Wš“£ú(7[ póŒî&}†ëÙþ¯[nn^>àcÜ}¥´¢lØ ÉÀ¿/á­Ï²¡@µ¼;l÷aLuÿFb`¨ðxNÇí2ךpËñØÜéÌ%¼„·>OؘòQeRz¥ˆßÊO k5êÙM­XøÎm"ñ×¶öy8çH/áýx¼—‡óƒ'ìyÓíaˆˆs•¹:Iò•–S@ùÅÒè½G¬\ÄÆM° š{ƆÞSx–9¶k¶@¶ä¦ïÄ@Ö”³!ÌäLµ]g$«„×òñ:(è[Ý{:I÷&^Âûñx¥ñªO òEùÈ·‰#<™$œë DsŠ/tðÝ%$3¯àÜTª7­¨øv+ÙžÑl0ž¨¤#¿ËcDs‹ÿPö”g/;2<¯øÕ7)x¿Yh4Ó0X´,k¿`Ž^®œðÞÇ›¤k¨¥¼ÈHË€àžE[‹m}oî `Ñâ K&Úûá.R•Bð¢‘tJ#Cݵ‚¨…½ÆÚË¿Í%§Œë,˜ XÕÎØPYFÞ/o§M—Ú^Âáq/‚ðÞ)eSœ ì×O~8lýÝ7åí »æ•'Ú“,X ^ÎGÔɯ_¹6âBÜÅ.¨q¬:Ú“¤Èõ&HU*\ÁéuHl¶Ô~½æF^Â[Ó'lØx#¼ÀC¹æmÒØ[~ðí]¤1¡x¡"zÒ'·7a©;ŠZ9½dîâ‘zºßW!ÐêxõõÃÓÕBŸÞ^pYÄ)ÇËWyëW ÑÈŽ|ˆ»÷•^Â[3x‹z•¯þ»Â;i&@øºÎW?-<3c¾ú_¹Çz-÷ÙÝÝÈwc}Ü{kuv¥Áv½ÎÚ3¢ÇM¬?‡è™ûµû™JðTKË(pZ§µ%¬¼·!ݸÇN^„š¶îá%¼5ƒ·Š°rÈX9d+d¬ r¹ òÒ§Jæx’ʧoe%ƒrä2@†òŸ±eÓ@õß(cYär2¶Òo ¾ºKx o-à­f22¯Åÿø ½™;ª/ùHkôkÂKxëoÌËû‚Üá%¼õ‚·&Bx /á%¼Ÿ=Þ§é¼G¢ÛV¾õUOø[Y[_µ+BÂåkO/_àÅ;û«/á­M¼òay›£ôºïâõcn„#zýwÏ×Ïådnøù%Ø!Y¼œýÄCÿ;ÂKxkoÅ\e¬Üe¤àÔ:JF¤Ë€­ø­xe=_*¹.v²¾}…·ÍR7¾SBþn´"¼„·nðºo¨®÷ótídø­ÑÔx„‚]ZO ¾8ÐŽ=ªþ&Ys€ÍžÑ/f ½þ¤˜D{£•¬o:€³ÝÁ×N(ìi»S]žÃư"¼„·VñòT}Ë+ˆ™ÖÜþÑz†«!6°oúzí/ XÉ!ÌYÜ÷Ï~q“ã¶ogÄJx»ðø‡f€]:ÇüVco,á%¼µŠ·ðá£[*ÇÙ—,äΔ8^`z›qú÷À¯Ú@'Sp¹"X)ÀíŽR >½õ!Ç'#fVà=ßÔ`Aï@gûdê‹Íë°„—ðÖ*Þ¼›6Êûo[Ç(4YÓbÓ¤nº¶@á‰=ö‡*Ç3Kñ*§¸Ô ¾8tûö=ïJGÞîLÕÖíÜøö6»ÂKxk»l()ÏÝ¥™7ùT6rÈï*;us|ô ë9$¨¼D¨r:€'‹€' jv@¨[¥#o7àu»pÃz>o¤šá%¼µŽ·bZL¿VÐ3€läÃ(󾿅_›hΈ4c¬r1®Å€`ÅÞÈ ŠnŒ÷ò_ð²oö–fñ2Ì^‘$Çv•l`ÕO9„—ðÖþ ›n\YóD|Æa¼>°å`$pgë¡d¹ûö˜ìzvHÇ8ï–ãY€Ó¶Ý%Gì@•ÀÑ@ç8AZç…xs\ ¼8#p½%á%¼µ‰÷cãÏ<Œ¯òâ·Û~ ¼„W‘ñæš^|U帷/Þ!¼„W‘ñ~\/á%¼„÷³Çû*“ÿ¬üæˆdßÿ¸y‘Ý-WDß¶½}Ë.OnÛ¤÷Xˆœ{·’]oÙ‹ /á­)¼òŒ NÜ>o<+F•ÝXñÞ M‹ü‡Íç0G<°ƒ¹ûpëälÇë²àÎø ÏD3Ýó“Kx oMáÍÿ²bqìW£Äg×Wë,ù's¹*ž}#‡¤ãuü¶8ýÝAà`à÷Eá%¼5†·bT™Æ5ýNS´“ñVCSÇ5eÎ*·Wì¸4x›Í²ŽZkS!7Ó\w ù۔慬š( œ³ ×&èß\½R -­³â¼^¿á]Ïãä»Yw,ËÓç„—ðÖ^®jÙnb%3®õêᤇcÝgµÉV&…µf^ Æj€§“&ždd©xÊÁ>h$`u;³}ç(ÎýÆ,ü£2Þ"±Kï`D6I8ô¢gJà_,á%¼5‡·èéóû*§ž;¥„ƒãߎ“˜4ðA*'z«f>Ln|'ÁúQ@†§ËÜ!@ŽŠ7€GM8¡ÌœÈÐ_ÏÕU[­ïcÕM+{8’Þ7ïßvq¼kÂKxkoî•k”w]³ŒP¸uCs½©]õï9G†ô:Ìžì L] +¥áFsF u–ÁµIƒ+ã=©Ìšm4¯]»áTùÈ+•êÍ`òÛïo°H÷HÂKxk¶l(_õ]–¶}}ú¤ã)Atƒ‰?ߨ4xÁ¤áfs`ãHØ}-…I? G9 H€'_ ±G˜½Fžò]*ð>ùFˆÄޝ€‡59°n»AJx oÍâ­4ªlÖÕ¢^ad#œ“¯õÌØÕ6“ és7YW)÷Wã¬âßzåù´²‰Ð%E-¯Axûë ã;eç—àñ0÷xm«r¼s&Z íéIÒ„&@˜ên^Â[³xybÊš¿Ç¤ïÀ‹=Æ{"Òt×_ ÈøÈ½/²ƒô×]ñÖZÚ'þZ]އšV2ÀAçúƒõ—m7jg¼Ú²åaiW™/ிnW×)ÀÑ—ï@x^Â[sxÿ9Yæ€E_·m>‡¹[å‚XòKºHAxë oΔ?NNsúÀÍóvm³¨r>Ñ¥mûø„—ðÖ ^ä¿É©ÅOBx oíá­å^ÂKx ïgwWp¦QÉò­>kµª~‰,¿â\L`[ÕK8 7ž…›Æ<=í—82](2Öå"^wå›s–^Â[SxE׳+úú%9,iJOÿXõ{cJ–X+yï–¸ª{žCxS)-ß¾[h¦Ú 2!=c&.v¤ÞÂ[sx+.Rä‡\ª¿"LðÓ¯µZ2—Njh‚( ‹ˆž(9'"/2ƒ+OÉ’ ¢’‘Éš“¹*Þ#ºšbílGÔ´ÃÀ“úy oÍá­é³YmüΖ붥!sцӫÜo[y€Ùê­Ë ¤¡sõõ7d+iYÂcjkË?§›©¼NÑltþÀà›€ËÔÍ'{ª9”à-Û ¬ãe\ï%29:D’³ELWØoâ«–·§=æÉ µÐh‹œ~×ÔË Õ⑦!Òë %)g¸Ñ(Ï9âÆ®ˆdžá˜ ú˜!·CÉHöÒQe_ººý97ͼߞ íá~„—ðÖÞ“mÊ+¶ú`y‰jáÆæ‹€ŽÀåVh” 5€ÎH<8w˜|<Ê ,Ú@QãTNÇÍæˆPMÆ/¯Œ·Ñ¥?:ßäãO\yŒ>VVÏ/á­A¼Âظ•Ûq1…†³:éõ¨uhw¸Ò ~ªÙÀ0]hŽé'Æu~W‚·}9^•tÜhŽpå$`Be¼ŽM€Ký¸À±Aû¢¡?oW:á%¼5[6ªz–5÷îÃ4;X¤˜´EFWGä©Ùà–z.òvòÍ£žú©L–G1®uacO„©äÁ¶r:Ù‚×ce%¼Ï¿aÁí} x¥¼J‚'_¯á%¼5ÝÛàVÖ?­{*„Ž:n3±‰£Øz®µ¾ÒͺÖFG؃KoœžäYØ}»QaÜš¯n˜]þ27’µUœ¤–¬¬Ú®®ÀiÈXàLÏ{¼¼vÛ„fg/á­a¼×òâÏáú”\H{ì“úüµ‘Žžrðu Ó€ØGÉHu~îÄü\ž…¿pñÌ|þÜK& uL˜°±¯ò[ ÑÉå痼ɤùðF•ðÞÃ[SÙù á=JÇóªn~(­ê5’&_^«px®ÕZ{§d‰ Y˜OX•ãye¡>á2ÂKx ï á%¼„—ð~öx…RðKþéTgAwÙ»Ëe ‹òd²|nAnž ¼Â¢b@$[TÈär¥„—ðÖ&^ÙïÈ1\€ï´>ÕØÐ“iï<ü­ß®Ìü?-0Zµ,Ýa@Ÿk`Ç\‚tÿ°®-î^Â[Óx‹§‡•·cFˆl–¶oµªÆ†xoßy8j|óì²Õ0$¶^$Á›3š_'¼„·¦ñV\¤ˆ0ÝØóòÔ™æ¹À[³'¦máfz5'ëÊeçKΗ^rŸË‘@ÂåkqVwQæÎà\½@øÀÌ&0f-aàt/øµˆ†Ý¦Ÿ³qù€7/á­i¼C"3^Ž6~ÑÉÚ­nCn¿šÚa=×s¹k‡MøÑõV·'H˜úøê`/äžeξž8óúcõkÂ_³à-ßãvdba%¼Ïõ‹P8è,Ž=ï鈃Q„—ðÖ<^V,ÎR})—.ä>Ú/uD1€_w‡Z'~•r5yX×OŽÁà†‚¥x3±¸øm1Í‚Msçú ´æ”ã}¿pûÒ5)ÀŠ……[¹ó5¹ºÂKxko’¶ÞF¥ú=]l;Ü><àIÐæ*pµ5Þíͳ“Àš±ÀpMX£×z à®ZËöÀŠ %óï*ßnÉ‘÷Ûó!ÚãÀÕŽ;ñûH— ¼„·VÊŽj)žõª±×‡,½ìt¿˜·°AkwP9Þ==9˜¼pÿ"íq£9 ã_äK*• Ž(d ¤´\ñþê /á­¥šWÙ½¬©{c_À®éRé¶ܿ]+Ö†kcs/™ ÇÀG…‹«í€U“p§à­î7 òËñâkgàr_¤c[çA¦ÞOx oíà-h]¾›æº%Ž)Φ•Gõ:þÁ‡x¬ ðxpÏǺuI[²äaŸF¯iù»çìæÏ©[Ðö ë6i½,/²··žûE£—àØoŒ6±„—ðÖ^ˆËÇЈ!—”|¹r´ _  ø"°Œ/’rE<1OÈñ<žˆË¢¢Ò m#ÖòbWHŠ%ËÈK6ÿ£5á%¼5Ž÷ýñÿÃÌ샶«1fkj•?pÖQBx oâMß|ú'7…”­òi¹ô=¯'¼„·vðÖAR/áýP¼÷$Š‘x5ÂKx?l× lÕ[MÒ»ë·ôuÞÚ5v;)F®uò¥¯ƒð~XÙðDA>I¶:• „·ž°Qoá%¼„—ð^ÂKx /á%¼„—ð¾/wI$á%¼ o¥…³ /ámXx+nÀ|­¡¯¯¯¯¯“Œƒ›ôõõõuNb—ž¾¾¾¾öÂKx¯\Z²’† Ò²á%¼Š†7QKo£Ò|½ åéãããããÍÃ[oï0úøøøøxE^«ØGÞðófffffs`cjffffúÖ—ÌÌÌÌ.>&¼„W!ñª¼¦6ÂÛ0ñ|çEx oÃÄËI /ám˜xë7„—ð^ÂKx /á%¼„—ð^ÂKxßßÛ ”^ÂÛ0ñ´ð&¼„·aâÍW.½Âöt…ž£Ö.ºgÓÞTù‘ßö ÷²Ñ댊/áUL¼ÕÒ+l¢£J>ɽ¡pÊ5ÞÙÉœøNØõ]´l‹+Kx ¯âå½uW± ~“gf1g>îwönì‚ßvK6÷´è‹©l ¼Šˆ7uûnåÕ{¶øÀ™ÀÜ90kºw÷î­Q°œèyþÄÒ—g©æ%¼ŠZ6ˆUK[¥xïu˜‹¤îFî=Ü /áUT¼å‹Š´Š'OL:Íy6/ÒEÝùâAƒ‹ /áUT¼Å³ÃKî«fßs7ï>Rwéìàp8w„—ð**Þú á%¼„—ð^ÂKx /á%¼uŒ7¦H.%¼„·¡à•U\þòóï/ ¼„·à-ìP±*DÀhöòZ*oCÁ›¯Tv ÍsÓø.&êãõS ÉÌÊÊÊÊÊ °¤•Í^«xx‹T=K[‚¬©'RÔ¡Ùû‚;yÑÜÜÜÜü|ž•´®J/áU¼²¡|T™Ø[wïè-ñ@±§····÷ëlD{x{{{{ùÊ/áU<¼å£Ê€%æ¢AuûI/áý¼Å“BÊšÁ)ëx„—ð6¼õÂKx /á%¼„—ð^ÂKx /á%¼ÕÃ{.*ïˆ7Øê€×; | /áUd¼RNy;_=Âu xɸ§#7äSÂKxoÅE QíðÜýë dpoTí, /áUd¼ë°yh«1l½@/îò /áU|¼BÕ€òöÌ»¢Éá%¼ oŽåÕóÊ;¯šG úŽ'"¼„·Aà帼x¨ræÅ³t…ú Ûhè¥iCx o)¸ªe»IzÀH6ÝR*#¼„·Áô6¼*kN¼•Õ5T6Þ†‚Wt%«¬ù(»à¾´/Ú^«Ðx«Ê+Æ*±÷¿4'¼„·¡áÍ·¿ýQwî§^ÂÛÐðÖ]/á%¼„—ð–…eÁÊ /ám8xÙ•þ x@`Ÿõ¶pÑ`Ox ¯"ãåiÇ–·‡ØOà¦T­¨·ð*4ÞŠ‹Iv¨;.™çPH)oÃÀ[1$2öúÐU7Ú»™_ ïU]cccc£4ÑáU@¼c€‰/ †æ£òåan^~~~~~MqJx o’޾†Ò Òh¯.¯,‡‡fUÆ›''¼„WÁðÊ‚tU_  hçŒÞ;ÔǘܯŒ÷ºÉŽ;vlßGeáUèšÛaò3€F•Þ†‚÷‹r¼“ž&öÍ!¼„·Áà•'——™bq î_ˆ á%¼ŠŒ·ªx§u/ZÞ"¼„·¡á•erÀË(”^ÂÛÐðÖ]/á%¼„÷sÇËn HZþÎÄþìÕ1Ç {ë¨Ò§ò¶¯_örUl&^Â[¯xùFñåí¤Á¹§üíµƒJÖsMcÊ&Ö9Ø[êt'ìⱄ—ðÖ+ÞŠQe©Îûû<_µà’à§¾{–4r# ~ý*ªlÅ«ØéÝ]²ByÀŠ‰Âž½%¼„·žðV\a‹²²ôj»CWra7ÿò]`6éŠe m×jØìVySòª€q®EÙ3n%xO®¼²v?á%¼õT6¨ú•·u-šÀ7éM‚‘Öé ÛkÂJ­O™R¼Ð p¿x ¬˜ˆ î ÈîèGx oÝãMÚd¨¥¼ÈPË€,9°›×õ±ù@ΡMÚÊðû"¶£ ¥Ò²Úƒ¼R¼·¾624ìø„ðÞºÇ++*JTu.*(Ú6£çVõ‘÷€éër“¿ð€ÿ™ÀÐФW·eaQq>ŸðÞz) T=Êš;Ç'hw±L 2{ÜBv+=Üé‘ {¦¬«LÀû"X;áÝ_@¸)šðÞú9aSr/kNz”Ò;Nÿrnʶ\ÿõÜÙ6¿xIt×XlQÞðÑÎ\`ÃlŽõØÅóÏn?&'¼„·^ðÊ¢eÍ$¡0±ä~Ÿø7™1¡Å@j`vzH:؈à☒«é¡ÁÒ¸¨‚´°°$ =0îc> á%¼·~Cx oà ¾÷àÁƒû „—ð6<¼onÙÚÚÞŽ#¼„—ÊÂKxko&_–&+yIdu&çd—7‹£Â9„—ðÖ^ɯàA% Ó~®Æ†M(k¥Î20˜@x o]â-êXÞ%¿¾²´}§u56Äf–Ä{Cå„—ðÖ!Þ|¦ì"…·ÑÔÎ;ŽÝœ <22;ѶÛR’¶l¾¢sÆÙð2 ‰í6 x«‘ïžýY›ÏIò¶ìû׿^R p½¥ŒðÞ:Ä[qy¸(jÒ¡°îN1"<ä2ùg¤ Ö‰tÌÓg}çûªóÄÍ zÖÇÜ›Œiììawƒúœ‘ûšEÞ´S1f£ î$m*oá•dfE©:de–\d“‰%0êp¼pq´¨@Sˆµƒ€¡zÅäÐ<™$\úNˆ¥Óq«9‹ã%8p8Ï8ŸðÞ:Û¬o¢£¼Äd“þ­ m.÷±òZYV­¼îž5cášHÓYcÜv àþE,Û+&àFsëF—lëâ‰ÿðI/áýˆ²A¨ê_Úx²qºó/Ú¡€úYÀ´%Ã¥["ÊñnQ“aêrÀý‹|X´VLÄæ,¶ Dd(á%¼õu†u0ÜŽ/,žÙ€ï·¬ Þ€=Ý ó;.ܘ|˜µ–Ž…õ÷,B¸àÕœB\#¼„·nñ xSŽ×/i~1ˆ®:zhÈQ>äSŽF8>üeÒ³Bƒ¥ÇçŒwŠÚÐï¨Ç¢A—œ'Œ:³|à~¼uµŒƒÁ®v#¼„·nñþC¤(ÐåÕî'!¼„·vðzëÿq„—ð6D¼…ÖŽbÂKx$Þ:á%¼„—ð~öx¥ßˆ´´w Ý1KªšÜu‹ë^ÂwžâÜç^Â[ÇxeêŠÔƒÝú‰Dµ‹f‡LÎK=™»UžÈ¶t»Ö˯ÇT,”øká%¼uŒ·âÖw¹Øq$ÿw +¡’¶©=Hþ6XlÍfOåvФ`%€L ) ¹´äo„²„—ðÖ2Þò‰ö^kôï§ß~–vFð"åu·\û„¸©=P°CgýÕwêêµõf!—„þ¦ªq œ½þ<5ÕäH—4˜Ò¸òÛ6䦋wïbœAx oíâ­<ÑÞÌ›üþq<q€Z7µ‡Dc7 ‡Ü€(ý’Ñg±C¾Ÿp8xÒD ?¬GÞHb€qøÑ-q_-Û™*omâÍ·½g¥røžMÉüÒ¼ ~ãe(]‡mÄMí‘ñý±{ö}W@´qéIZñ­Eš?Ç£&²ïnWJF¯ÚXaá|À[)“ðÞÚÄ[p÷þ5•#÷ï$(4ZÑRg|wíÛïâMT:wÿ¾ã;3Hó$O™T†÷GÛ2¼cÖ­¯â×å@ 2á%¼uV6È‹öl*žz¾HPZ6 Ö…¬©ò»:>î•ß¾é-€cáð4Qüx@”R 0v=Ðút'ÂKxkoÅ´þ˜b×= @¡%ó²8·Ãœ¤PæÏBöÊd¯—óßÀÛßJ†éhÏö~kû‹¼~|°E*‹T>œ ù#ƉŸÚcrnâ—{ #]Õ¢#/á­ý#¯IùNg3‹„ì6Úãc¸åÖi£ÁÀãÃJ¤)ê~mߎC>€øòf?ðϙ܇ä”Ñ”†Æ>7Œ¶#b×_e^Â[Ëxk!i'†ñ /ámxxóçë,á%¼ /øI‰ÕÄNx ¯‚á­~/á­)¼ÏÒyDH¼a#ú í‰<­o$^Â[×xå‰c9êA¯ûŠù'“÷Þ÷®²ýÿçìÆ<2ò‚ðÞ:Æ[10‡e]F O­cïF…¥CÂÞýÛõ8[ùëúX8ƒðÞzÃë¾q ºÞÏÓµ“áÞøŽÑoA€Õúõ:©@ÎÖõÚ•h•Y~?rK"2 µ—[É€B“µ§41c,"¼„·®ñòT}Ë+ˆ™ÖÜ~Ñ^3vО ¹I$ôçÆ}Yîâ²âBíŸHîè¹îRQF؇Ÿ^Â[—x :Ú¨w´/¹ÛG0(!p¼€»rÌ:¹n¶´N4=\>ë¹ÚIìÔÒÜæÕØ.xM'l„·NñæÝ°±PÞoc  ÐdM‹M¿vÓµÜÀ¼òçiÞÚÔ`íçužW¯Ý¨ó6ÍMQ¨êhþ`ï\<›ðÞ(eíÉsviæM>•] x4*„eø1Ù¸Óð#¶ÕæÒ×÷:#ÎÅäù@ÇKt»,ø@Rá%¼uŽ·Ò¨²éV=#ðn0ÁÅû¾MIèøgÜÂ/“YmÑýËæÎ™²éê#ìíãÿœÙ]ÓÑ^=Çy “/á­û¶Må³;þ—qH z§ö…à-Ú—äžFXiŸ—$œÚ¶Í¹ìE!ƧŠ!\¿¾† içÖ­+*ÁëÔÈ‘cMÍ»Œ—p7í8=׋ðÞ:.TÊÛSyC²¼QÉÎDÖwÏ‘­·¯­­vò¶%xñ£-2ãq÷@œ˜˜^Â[wx“ ·è*/Ý¢ç @^Ó+øþ˜,>॒ ô1€¸©=’•CàüZYAzÝhk“Ë%x¥?؈mgLíµuËÊŸ9„—ðÖ^qJj¨ª]j2@¡ÑÌ.†}‡èÜ)ÅÛ×° ¼;‡§µ¶¨„—?i½¿8-5#MFx o– …ªeÍ=0íªð€þ[€ïž K9ÎeÏ$@kŒ[ñO×ë~tá±à÷Q„î^Â[ǽ åË®NxÚ# €ècž÷ªÙø˜ÇŒ^’5s$3¶Ûží¸7Zv§ïéS_¬JˆXñõ#©«²f´³ÆâÒÔΚ͗5é„ðÖ-^©Wy©Â录x{z‡½vÏòtÏyãéVˆX—< ÜãU2"ŸÇ¼y••úÊÃ_æñ*=ÝãÅÓ§^rH¼]þÓÄ „—ð~Þú á%¼„—ð^ÂKx /á%¼uŒ—+f9r@Æe /ámXx¥¼ÃGð€ aÕº“=ÕFö±Ÿ$EðÞÿŒ—3!¤¼5Rr{ yXµT:1ýIüÛÑ×Axÿ+ÞŠ‹açÖö4ûuÆ…\Éus‘üÑ™WÏϽ$Î_O ?oýö’ 9^°-ðü¢EP‚~ãÓ®ùI<˜ãôuÞÃû°¼]1$2Û{ì6Ï.w|ùr+&‡j?0è˜Z,¶þêviÎ^æ/¿5«%RCßÝ‹²í«|ï÷»ø•{üG~’è–Êké !¼Õg@éü7r?Uõ9ŸWrG;;*0y€¯J.Ðo5xß9bü Ö6_å"¾½_Pûq^›§m¢ûÜgM¤]óvc˜ŽÖôÞj'«céÌcI:úÊ 4<¯·³ÞÛß>¤lT™$Míá3Eí77ÜhÈZ?ð o·JH­ü»žÜ;Ø„i¹¢g y%¼ÿ’G?1 Ã0ˇ|àÀœÐ‹çìDµƒ7Àm¨/ ûåXÂû/ñË0Œ²ÍU&Ë ‡­•’XÂû/Ùþƒ*Ó-bð{ð ¥°ðY@üœØÂbN^^‰?/ ¸µ9‰%¼ÿœ‡-^Úü´˜7 j¼²)Þ‘c¹\ÞºXyâý›ÿõóc#£‰Å°Y\#xaÝÂÈÞJjçC€¯› ÒÀœâÓåÅŒÙ.૚D&ÿÓ–úØÂšÁ+ÓîŸGf ïû#[:M¼oTYÄ¥=¯Liž ÷Fù¹ ±5p°LsõJÄ»›êgDF"×ÒŽïåÙ^ˆõºäêgæyªèŽ97ÎòfÜ;ñs—jáEÑPM2Kxß‹ö%+ÿT=Ñ^Æ‹ÑF®®½*†{£|¤¶Ù ódVhŽ.‚Çdûû_€4´t8À%zÖ(Öl þ3¸ºû³ã†µu¿ÒÝ_ìÉ<Þc¢³0/FÏ· v¯ZxÜæ&¡%¼ï‹o+[¼‹—K²T_JÄ%*ØÑ~©#Џ7ÊëMÌþE4&öL€Üþá%ï<ÖÔtŽ p¡;¢vh¿X8 èqÒ&Hd¢á¬œŽc­Å˜¶¼zxq£5•½„÷=á]‹¿áMÒÖÛ¨´@£¡ËÝ· tŠ,Å;H⦠6Sõõ—k€¥ÓÇ>}í«‹æ­Þ\Âû÷HæÎT‰ÊŬ\ ’bQ±\$àó¹"®„'âÊbNé?èRX®€WÌñ„\>O(ðB>_$rÅ€€WÈñÄ<¡@Èç «†SÙKxÿž?:VšÅQqgÌ)´‘Ê^Âûnü[Ú !à…O«[D—ðVg  ^\míOv oEXÃwKIEÆËjô/ ¼„·MÞᘗτé¸Ñ\`îd@í4ŒÇߥ Ûeà÷®e}¡œ Ó–,Ï€UkàÀ÷W’ó0m SVL;üF®šÀv¾îùeà×òá%¼ò壋ß7û’Åiåm–#íÐjn0³«±àÞ¨æ€å“%·YZZ>+Å;o vK¦‰JQhjœï^Ž·1;‹§Âª5 ºòk§ iÙ†ô: ³Nÿ+gD*ÇËš<N÷ú¼0oBx?{¼Ö­‚*ÊW}—Æn^?ápt6ðºQ,:+&£Ë Ù×›#˜7P;…£Yx6Kƒúà`ù ÛËÆ˜v–LŵÖ@Ä~?îŽ÷†RèÕN€à+gD)' —°ï_ñ²ëGrïgŽ7¦]Uƒ ß½‡íUYó·Ë\õb{&NðÇ…¼C8—ƇÇ/t„ÃO»PÄ.Lr]ãE®º áý ñîì“S-¼)8q–ƒc7¯Šó’²… é¤iq@žüíÙd BT’²ê/¼ZÜ ¼ŸÞÇÍ^ Zx+&Úó6ì=zkË•&Y¡+›Þ5û°¥îL_Î4žu$Áªç÷³©c¼8Ù6šð~fxÓ»îGõðŠU+îÑ™î œ €q@x·W8ÃÅ#üè „yˆ?ÕäuŒW¾f¬€ð~Vxå g «ƒ7uÛ.cåU»7û`%iêÑNãŠe€»J>Ðwbîü­- ûÁ@°R îü(­c¼Èí¿•ð~Vx­Úýã?¶åxùÁ¡*×Bßæ(ÔŸÓaÓÀ~š6€»jÐwg~Ÿ?BþhUŽW¹^ð³Ù]Âûá n}Õ  Hµ|þ½½»1í¼fü‘ÙÝ>„É…E @öCj¢”³`ÿê/þlEx?¼¼1KQm¼•†DŽ¿›Þ-^«|°q,gÌzÇ™_¸JØ)kw¾-<ÍÜJ3fžIê¯|ÉDáý\ðîîU}¼’Gå£^r^ÉÀý˨‡NB óÓÛ‡/$ȰóE‘£ƒkú£‡/ê/²{šÞÏïÓŸ\Q}¼UÅC™[GŸµZxñ²¹=áý,ð¦õ؋ðºûî|E‹Óí£ïg€—];Fð‘xå2ÈX…Â+ž;‘Gx?}¼Õ‰ÕPF•U$³ÏvÂûÉã inÿŽ÷xxÎ~>ÀJ /¼›?"¼Ÿ8^þØêÌ,þNoÓŠEsúÄ<"|Û)^œèCx?m¼zçâÃðVôóòÒ¬‡¦ìX“&Û«„ål^ZI¡™—.)ÊÔ3^éì BÂû)ã}Þ̈·bT™§^ï›[-5̈_¥¬e\]ª;û5‹Ù[ÿh±ôM=ãEr}„÷ƛѫz§5UΘ`†½hP¿F"É0í'Á›nÁp`Üë»l^5{@x?ÙÿcvÝ(Þ‡á;pé„ò³³áÀf÷‰~1ŽÇ–®€‰Sƒoù0ípTŸÕ?^ì”Dx?ÕX¼÷ŽË÷áåùú¹¨Xøyç(ÔŸÛNgˆº†M)ÞÂ_7ûžýšÓ½nã§ €Wºp²€ð~š ia…Ä €S>?/öîÀ´[à¦Ê÷“Å1Ñph,Å“®yeáȋ잛 ï'þØ5øx+*›p'£k"Dµ9i,æÌXùlã,­Ôq:ªeð¢™áý³¥WÎÁ+¶-ï\sÉ+r–ëgäÛÚùß~,D±ƒmT“ ';FÞO/.Ížã¿àý×H $¸Ý#U1ðJçŒÞO-9=¡vð²{Öi¯xÅÀ‹ÔÞ{ ï'™öh~-áD|9/^4w!¼ŸV.· C­á­Å|8^üÞ5‰ð~J kmŽÁË‚Ut¼¢Y“ù„÷Ó‰`ÂJyMà•Ï÷Ί^I/’»"¼ŸNvvÏÆÅË]Yq‡M°b»Ù¼¾ãųæ ï§—æÎøÏx+.RÄÞ0T³;Ǧ0ç°ª…ÿä†' @à`›àh›‚7s/öuJ!¼ŸF²z~hïQÕC"í†kÜïpΞ“w\õº°oó½É'ñ­G»˜}éû<ت¥xųfIï§éŠ*Ö¸¬>ÞBÕŠUßÇ»ç +àÓˆÀƒ‹»mDpê–‡æÔ4!²S ¼Hè|€ð~ ¹Ò& ÿo¢–ÞF¥ùz=ˆŸwzrnˆwré¨2Ö{ã¦ÙßVŒ*»Û{˜q‚‚àÅ“Ÿ\oÛ_u¤/+“媺Éd,î¥åÃ/ ž{öUÉÚÃHoyWæü{–Žç-v\Ö:\AðâÏn)„·¡‡ÿË ùÇ _¥¬æÅæ¿0é¼V-¾.NTõic  kž0ϰ®)ܯdêb)ámàÙÕ?…· IyÍ;Õ%qPdO\|D*þ}ܾµMŽÃröŽs_>ÅžuÆ+ð/;!¼ ;/Zü—cae¼l^ù‰{¡LZºs©bYé¼ÜL›T‘ÖÔòì”ìÿüÿ/î5AxrrzïÆGâý÷ÞŒYî)ÆÓki¶¥À‹Ý=2oÃtõÈâZÇ‹‡[ åBñðrÇ/Þ«ÖÁ¨}¼µ™Á‹ØŸOÞ†š¨ö¦øœñâ^swÂÛ0#³LVÃx# Å!Еæö*¨ŠYÍäo½Þé„Mr «¼ØÖ#ð6ÈüëìýÕÃ+©Á+èçß_ÄhVëüÌ~æÙËkgüÕ-{ÒB¯òã ]k ¯pÚ|9ám€yÒÜ5€·°mÅnòÍZ®àÅTgrYg3 wvU÷,4|ç¡YmáELSÂÛð’Õmjo¾RYÝè¡3¶«±Úx½ô¸ÊWðp‘Fd–þ³uÆ·õöäiût½Ó7%m¾[ ¤H./0ÈŒÚhpiÉQ; çÖÝg1`µ¥–¹ð6Ö¿Åg»Õ^Ø5÷ ¼ -ò5“¸5‚·b6aδSij^y2éãFq\ðÖ¬ÊwY`ò´Š‹¦Zý9 ¯_–¼áÊdÓ·@î°Ýr™Î‹âi­£ƒ:¬N¹ûs8†ô‰Ža ÏžI¿^¬U¼Ø¤žGxXn¶‰ÄÇã„…{©\-™_Z:,*jŒÀëF^öÍ+Ò(ÂÉŽrD5vèáÓØ í,­–/mÑRWˆócÄ©›ä˜?èq‚o£ß:À\‹—7» k/wÜ*9ámP‰þ¨Z¯oÊÖFÊ+wûàšýÞúOÞçÜÊf‰ ¶{~8Ñ(ú2àò÷»wî4þû|5…6~€ì.×oóf½OAØÄý GM1LxѸ¸Vñ"¢ÕEÂÛ"¿P^xQiÕw±¿þ€1Û|·/ŠŠåÀ‰_ ƒYÄ6‹¼ß@på®x» “`8×( ˜7 è}Â&è»°ì‰ùË;j÷È ÜjáExPöõÊB áÍcʇö,¶ö¿/ƒ÷ò€¤ÖKYàtc¾ÞlQÁØ ¼çóòàšEÉß î·ùü›}¢ßo¶âi“$âÎG¤…ª·y}ºÆ§:…WýßdM; ÉíDµˆ[{gÞ—f7]ne¼ÅSCËšÆ!)|ì]y—°è.€“Ýïê§ [µwÇ.-yýý-ú›¶NõìfÏz|kú ÷S“×hÎ8xvÃI ધc)…ó²iŵˆ—;r©”ð6döÚÃûÞˆùÅzùÎõù—òÙ£ÿx©¯fð"¢ÝÂÛ0®ͯ¼³_¼ðG÷®¯Ÿ®Ûé„zÅ‹;-^Þó6!¨¼"—WÑNOþ/ç±[ÏxY}µ\ÂÛÕæ£»† û;¾ç'µV;¾gž…tõÁ‹¢1X«ðO\óÑò…}OEEV‘¨ðC‘µ’ðCAUýÆ(×Î>5³["Û\&¼ ŸÃjß/Ä™ÐôçU¤óOLûµ’Ÿ•¾ëTÕÓmþãpúÿMK«àyѬ•bsÓÓªJH'•×iµ’æß{TùƒÌ›·Ic@áUèdöÞR‹[ߣ¤âZ;[~û=£QË»†óË«Èa7ŒäÕÞÖÛ3L- ½×ˆiòª–wNH+ «À¹Úúm-þÍXÂ0L-Øÿbflmßë{µEáUØD·=_‹[öÃ0 kgÛz Ã(Õúe0­aù„WA#œ´¼‡®rF2 ÃŒ©•Ã#;Ÿa¦smÏW4d5áUÐlíU›£§v3 Ã0½jeî†afMm_HnoNx2®ÍœkqëÅK{|¯Ä0?„ÔÆÆÓ;0 ómש9µ½n´!¼ ˜ì^µ¼Nîýïtg·t«MG·lø£eL-ÆjüRDx.r1‚Zþð$ùµRóJóÄì›u±›òúm’^E‹e«°Úþuk³&Õ[_'ûÉ·ÅM«`‰h]ëMÒ×jsó×Õëæx©MáU¨ðƯ®õ¯>B-¸67ïשnÖ –®Î!¼Š”=ÝjÿlçNŸZ½–;ðnÝì«Üÿ±w—QeÇcu{]×ÖuÕµ»Öv펵;i•²»;PlÅDì. P@BB¤»{˜žù>/H÷ÑÝUaüó{Ã03̽÷ÜwÎ=çwÎia^ŠWƒâN•‡E¾ •é´¢ÝÀ35•–kõ“¥x5&"ߨ†šI›¢ÝÀòÁ 5•×Áª¯JñjHÈÆôSÃüõUŠøëãó&›øˆPêôÈ,Å«aõë[5låP§">á±Õ<ÔUbÉ­•âÕˆp­f«ŽÍŒŸUÄwWß0³g•íJñj@¤µÓSGiF‡"Oå6Ÿ¦¾RÛ^çM)ÞâEíÔ2­ûïE½‰Ó­Ô×s«Û_TŠ·¸ãF5WµlçXÛ"ŸøàEÓõ•[LcU)Þâ°ßÔ³Ö˜jZÑ·Âf´¾¦Æ’{Vå|)Þb ɈRµl(«þõ¢ßÈ€-ê,;Ë\íý"ðîü-X=r«XôY=YS‘J'öÈ(Å[|áRÅ^M[ÚÔK ý ›¨u:¼¸æ‹Kñ[$·«®ûóQFjØHd5õŽMwªz³oqżvêÓ’ÔVw7Yª··6 *Å[¨rõKÃkÔ¢Ý ô{$*j‚wµ(Åuq­E¹xy\Ëx»ËNçr X×€™½T?^—Ë%)±·SOɤà]1ns³y]”µO~;¬É’0™àß$ð^Å,” ¬3 ÚnVÈäItÚHh]LxÓÚ\Qãiq¨SL®.òňÔ÷~óf¨Œz€Ñ$ýp–H}°¯rÊ Lº°Ö8VÞÓ&(ÛN¯r™ØÔ¾ÌЇõ‡2uÁáëôiõ“ØÐE©ßùïF`6A…õVÌÇ(9µ‘î7 Íh)‚û¸ýî˘a°yˆËKØ=@ÈõE´5‰xZx_USçÍLXs‡âñ 3XôeáåÄtSë×[Õ>ƒcwƒ Õ†¸ §Ï5oë=Ú|þ'€£&½¥¶C¦lmÖìn¤N…M®#~<îÐêW»=ÓeIrC³ G˜ÒâÀü¡Î¼ê7cKýÖH134™NÊ<3“ð[hn>o¯Ôm\åÍ‹‡ƒ1Ã@h1Ëb^â:¦ú>ìþÃУ8ðè¢Îv9yïµÅ"¦%9üÇvÞ„à$’#£ã!-$5)<IDH"d„†d½ÅF„ i:d…ƧF¦H"â¢3"cãÒ¢¢‘……)@†¥‡¤™! ©‘© ŠʈP1€<<$2ÂÅ¡±ªTÆ ˆ ɈÎUL\±T&ÌVëy™3¦¸DÜÿåÖ†·ð¶7 Ë®Í%.öì¼á^W'^Q{+µž›ö)ÅEbGý°R¼ï ÛY3þóÌ„òc†;ł׻‰—ZÏKH ßâ"¡ö—´oQ‡:ñÚ6UoŠ­¨UñMÃ^õ—€w FÏÂæ¬F¼æSÔ{l*ݹÅW°WªÜ/ùxµýÚªoxu/5Ÿ˜çŠÑxÄÀ¬_mè›.Öàx ¾jƒm»d5Ÿ˜¤ÖÅ9÷hxƒu%ï¹&ﻓúðª¿Ùµo±vÜ«r­Äã-mm@ÖkƒÚnéPEqîêz¥x¿¼ÁÔ~tw$gáJG “—âýðÞýUýc£jxké†6ØõEâ‹$$¯“WæíýX¢Túy%ˆ^ú|8%_áëêG¬›·«ËK)RïþšwíHõŸÑ€ÅKãö/÷¾¼»+f/“wpÌý%ëlù ¼h—)¿Zy@òß7™ 0»ŠA™½ûu¦¦ ÏO«ªÔx¼½‹a(:ËÆ³•šÞÚûŸñŽ\š÷Pù§sDÇn~ΙU?Uͳ¿kÊ|xaBYoàÁ÷^ÛìÑx¼éué±i++^’!£d_Þz¹uSí*Fƒ̹ ëæ/{Œ¢ò¾}.Ó΂¦»Àcþª+å‚<æ=[6%œÐU öd]Ÿ±áæœ=ò¼ÎÀõïDÐ`/œ©¢ñx7/ŽQµ>ÍýŠGx½µ_ÞΆ9äÑ›ÇÄ ]NÔŸG£÷HSU™·­Qœò¢ šî" Í¹ØÅZþ"kUŒ™o\ŸsqfÓR'|çîÑÀú¼*ü{\"ðnêY7Þ’f—Š[Ç5ÍNrøoxÃCÚL Ιîhž%ýž«;+‘Þ)]ÅÄÙâ€÷bËâI±Šnð¸øÜ¯âPòñênË}´kúÙk¬{š, oê9ÛkM·¦Ý…ïí=î>7g,:ñ§ÉU݆!€»±ÁŠð»Ãú^»Ñoèíl¼.à0µ‡Y4/û¬Új<^íâÉÉ—õׄ›ý-"K<Þ‹xÁÌ| ûÐt¼Š««kÞp "î=R^Š7ëd=˼ÏMÛ8ÛH¥Ùx×·÷™âB\ ~ÛQŠ·ÐCMxZÆÓ†Ö{¡ å|í—‡¥xK(Þ}=ŠëU­NjDA[4Žûrð&ÇýŸÝ„ú(3^úz¿–  ô V”4¼z‹ŠíìéiñÀ±ò/¯ÁbE—ÿZTTn) ÔÌ[:if¢äऊÉE…÷õãG‹ n4^ñä£ÿèÑ“B™Úܦ…f y[{{‰Æ;¾ÀD½ŸEwø¯=ÅO×À2ÉÈZ¬÷rE…W1²öŠ Ú5ù„?êT³P½yÿ¨L®üò¨$ãmŸÛ¿o¡WeîˆúÆ×!f‹éj×}½kʽ:÷•çšÞ/óy®kg¿]l¾/@Qéà]&zOƒ§å‹ o¿e©EéŸð7B£¾…q„é×'«‡–`¼r³Êd!ëG† ^œLl?«à¦­iÅíq©Á#|¶¸ÐV°%Ì̾ձ°™ç âM$±éþ"Å;@“†­,/œe›ÇéjÈñHú •—P¼qÑÑm§EGå¬d²`7ýŸë:)ܧ4v`Ó5¤A‰ ]õÀIŠØ¿â𔸄|¼>Zº†=·IН&5G.-¼ÛÿkÈ5Ú\2ñ*ךš×hm>ÿÀ­Sm檷íJ^Vs Òu²ˆÔŸeVk&<-ŸØýÙH÷MÁ+¯Oì”É”âýÈp«¤)Gtç—§%¶ÚÐ%7«Ìyw“k¦Ýî:‚yw PÂóf»­À¬¹ŠSáéWÉ IÜG´”ÀIðo7Jñ~ddÖ½£95¡&Ñ%þ† ëÌÙàÕÖAu÷¯tD6ðƒ “ëNQñX^…lo&ËÃûR†DêÄ«ºeùäÃP{.*â÷ïó,ðtÚé½Q{§ì¦åk Âf¿M$¸[æÌÂtË_x•cVi •Ì^c%%ïô¼9c¶meֳ싰±…pÄX )¦“·é{Û_·½®k æúäU^i·3ð'¤×üøçjÄÐ`Ú‡¡ÚÜV ¶ç.‡=~ˆk© øn/\ŸxÉÕ~ìu¢~Í~Úðïct”Ýî>^v÷Ô+Áõ¶”P¼ŸŠoNˆó3oÄwIêÀ«Ê’ÝuEVöxI– å®u3¥ãDà­ÞW÷@‘¥i =‘áWOÄÙïe_fYÔ?H@+7àY«ö5Qf)@–}L"1€,KÂoO‰T…Ž×¡A¢æ`¹]åÖÿ^å´é›2ò\vÌ—¡¼/ f-K§›¸N3c§B¼uÒ\íˆÔù³ -²mjŸùŶÚý|“gºsf=ádåVA¤}½uS¿³JÒ–êÏ>¤€'cW?ÄŠ>J@Þc–µÎ÷‚MCÆj}µ"nêΙ¶+cëWW&:Þ¨–75HËŠÿSx‹0>ˆ7úã$Œð¥›ØÙáX#-6¾8Zfe×[¦ÆöGˆAÆ·wc:>àIëp:,Ò˯æÌ¯É˜LV&¶;Etkkܾ:Ìðq ÇÞ¯½ØÓ)‰–›a±6LØíÑòîÃSøùrTT®Ð —.+Å[´x/WCtÝt@öôÌ‘²Î×u%š›?š:äÌS5%åî¯×^Q|óøj•³6§¿ºA;c ½ì^–’U»:ý¸S)jdDöì5ÃDz§ÄþäH«­È~wÎvü€…=A!SVºPx1ýK©AERe)Þ¢Å{¦jöÏn:°lèeÛ²Ï!duû–68ë7íî–7N1¸û¡ø›'g¹uóæÃ„l¼i_=Æ«L”äë»0·—C݃¬è«=×±§d|sŸV[ÿ¸êæÍ{¾3ûwgZøxo4IÔ¤2¿Uù^ Çëò„kÿ0Õ}«¿5Q ì¿×GžŒÿ#û‹¯ã¯a`Iw=¨zŒ´2®„¿Ãæ^I¤4žÀ´Dn|}Ù7Ož×K‚s´Y AøÕS|ËÄ*Û[ÁèY8WBXé­Ý€gmBÙWMÌËšÞ´ÚŠ¢óxû`w "› åWR“ oT5oºblhSòðhÿ³^Üä½9þ‰íýÿÆÞ}:\pÌŸ¨ZOõˆ"þYuâÅ+[ írtbj@ýþÌä²CpTèÔû±óäåV3]ït9 ðªÇm¡ÌOšå$Ø¥¯ã|H[ÈÄA®ÉœRmw$×úÜ?ÛÛ©öT—C³XnLºìb?áQÆ‚ã.cŒå´Ú ÷z\y:ópôFçus¤t´ØìRøxÅ}j^éÐÑÒ‡7¯“B%Žiïò¼cœ© ©$Ù•2‰ ÂϤ@ß™Šì?ÌiuŠÐz \üd5l€6󋸵Ayw¿M*·,÷º’qúÀãƒG‡÷ßP¤_=x0ûxí-%ÉÇöî­¼ne'„¨Cç%Yçöž;³÷L:žE¢ó\mözC¤Í~›(pß{Þe¿½Zm^:왬®JàÍÞ›òÂÇ˲±šUY‹ª¿¼Äáídó vî¨ZsÛµÖ»"^õûÎmCvÝ_4è¤,6Ô>–d¡5n»ú²g’Å[=½]Ùx½ó?+ Æ  uQã-ꈼN£CÿøŽÂÃ{¾•†MÕx½Ê’†·Kþ¢v{ôsP}·€›e±µµL®·a'ûô2ÞýÛfÅÔ¸Éø¾¤Ì*€·R|ÒñŽA_Þ˜YS'Ç« ïëf¾š…—õÂJ^Õ5Û û_8÷(ûÕGèé H¿µ'LàËoÅ •Ö_°o;9£Œ;@ïIPç(«~Þè&ÊÇkWÁdZƒG| xÉŒù—Š_áᕵ²Õ0¼’¡ƒE%ïÝ+W ºzùÀƒÚ£gTÓYÒﯢåÇíoÄQeö\½zÛ'>oŸPû(\Ó`lLþ•·2Ì®*:¼;5è/+4¼L\¬im” W—¼]ŒrdÝ}¢PŠï¯®À½o¤é¯óÓDo¤ú΄:Ö^Qƒ«Xú²ñýD¥xKñþ[Œ^¦‰ÅÝhaIÄk¹#×ùàÐô÷<) |·Ÿ~ʘÕé¡s»é̾O¦82³Gtà•jûûëäW½gæ¶š¦N áÌÀl í—Ñó»…Áö] |·Žùª›Ž-Æôg8ë™È¨·nÏÆÉp˜ ã·vì$uà=ÐU¡‰zŸV±/!xϘ`x艌ÿVá©eýž'ßj½ÛdYkUˆÀMÐø0 oAP!áMß•ŸYØ6ÃfD–­¹Ç$Þ‹bdNgÂΕ¿à5\´‡WZïNGûL­@±±¡L¶¿qldÝ›*6^¢\뢒﫮¼®54s~ÜuýKÞ¼NЬÇWœÙÛâfàóÈ#ð|ñŽž)ŽÞ*Èxö$Tîû‹Ås!ˆ<@áõ<áµc2ÂsZ6ÞJäîÞd_Ûê"µ¼`üPð+\HxC¹ÜAK;>0ë±ÔÿùóÔ '—w?%Ä=vŠÇû•Æ {~>ékùïIæ)­ >„9=K»Ô9 p3…‹uÄÐĘèïžZ&’6¼¼[ïî‹ÛF¾*L¼ñZyóÚªz¹Eý‘¬›ˆdYO*f²÷g1ûÓÓʾ€ Í…ìo•N%{‚µü`ÜH(“œë¡d¡/yxwÖ¾j¯½P‚[¥Ø3ÕOßy[}x7õÒÐyÜ«_Ðt¼ÊÕóM«·25¶HŒº3¨ÝÃx˜Ý¡ß"Êûð°|VõIÒbö½ì¬2Z<ì7ðû^„_ßÁ¯LÈŒë;÷Nµa›MÇ¥Þ7F&Ú‚i&s<y´Kc¿C}"„àÛ Ð}ž’{3yݶó_b˾€qƒÁ÷«ÕO9xG¯2‘@R«'afÒ‚x/¬oð’šØ™¥Ôz¸4H}x]ÔL¼®å­éWÞ”¤äö3““ÒvϬa0ê×›A»7= ¼¼+¤cUp˜SgQ6ÞäæÛ“®TÈ€†ð‚粦ÙÓ^åàõǽ†G¡á•%%{i9%'I8Ó~ÍÌÿiüTCWo¿÷*f‚ØvB•³)e_ÀØÁà]á}x1š4{^²üjü~˜Ô{¹P1aÂ&‘úðfÕ½¥¡xUS:§• :/÷û°ÅÀ¾E áÆÂ‹Íã9Õ2‰çdý磰²µN‡z.ðä|y4>Œòë'ø âîdÄ-ƒ‹“òð¦h½E9qRaVµ^å>4²¤·cv{IýIRxZQ…Í#è:MQÖ¦6Î`w› *Ý F+ Æ/Aòí ð¨3,¥Þ½-!¢öØ'Ø©âàWGP^Õ„ÅŠ—¤Žs4oþ,‘‹gÒç€r¥¡Õ+•b±ÑþQW 3ØNüñ®ûË}£N û—…"Ã!ÖÓ'ÒïTÿÖNkAdrÛyfiƒ6Nž‹7v«`Yε7GÞPOî³]¿n™}mH¯½D G2.ýupËPÇs‚¥QOÛüz`Oï+Ü.oà°C°19¸Y³ûÄ·Y`ž Ò?×ñ¯*ç$,üã²Ü÷Ç[ð¼ê35âŪ³¦âţеÆã Êë@ˆŒ#0g%é—`?—XHõðy“ä騌us ‘G óöˆññ‘¼õòLzãã™F¼k¤zºätÖÿv2Ü}ÜRÀÏM¡UXxe¾¹=Ê@‰0·õ8< d^>/%ªPW·$Þøx¤‡zDEºDA g°—§(ÅóeĹ&¹çâA˜‡—·¡Çk¥2P Ò`À©ÚêÁû¬žÆ.Ìñj/4o‘Dë[ò(=3ûûÐBÂ[wÈ}YÎt´®Œ.¿÷=)[¶RÞäv6‹—-ÿñ&„„æõ«bcšƒ7y²In÷‘,êíû‡ ËBƒÕƒ—as5oz—ÉòÿA¼Ÿÿ3‰9ÀæÞÍ=¯kï-Å[Š÷ƒá^'\ƒÏÄÅjK ÞƒV˜¹åÿ*ŽRÄdå=óÔŒÔÕž¿Û¦òÞ)ÑÝû\æÌèáó çxñÆbÄêBÇ+3 xkôŸ¿Ö²†Mß©tœÝîÜÙW Ÿ1d¡ˆë&pyÂü³‡$2^•XôY!ŽýýÚg~Äÿ‹wËDþ9{'š×<¤°wïŸCñQx/˜ùqØÑŒ‚Éý÷¿—T;Ÿ÷Œ×vTé_]|§tÆzßI¾­/C:µMVÖÆÖI ш¾…‚7ã@¾³ Öiç†þçÏLÜ#¿.ˆÍzPÏUù ª›JiP9ž s?ñAô'ã Öçó¢w¥º}ûjô½ñÎÞèÿ9ŸÕCP¿_5F¿…7/«Läz·á…#­†CÜ w!¤ZVx„âÕk^J„¯„^nq¾‘ ýá’Ÿ[&©~ª÷ "þìñ"xã$ºzf73Üý:Ðí åÜ` BÁ›ŸU漦Ӌ©:®bxã(\^‰ ÖÅäÞ^)o^¤"·ìÆà´¯*¦C‹]Hê!F§ö"ç)q+óÉx_•ßg{î³Âþ¹BÓõw¿³‡;úŒ=´½XÈ»÷Ïqò×#…7¯‡-åÀìÖ‡ÿ¹ï9aÃv™Š |ÁW» ½øí¬Ó ë«O÷:¡_¤•§Ÿ^846l~ŬÑMpnÕê?¬c5ñ>ý7ožUo7ðûÚ§Ððæg•=Û×júžë¦©VM°š²Õj+ýiò£¬Œ+Ķß³^6(œèÉë·Žò+ˆWŒü÷£ ;•Çkǭ䆟…×·V#ÞÅ»c %'TÞ¼EaË"þºDœ‡ÖëáÑ·T¹„ .w¡&Ⱦ_-åÉ×™lãG×[eàY?yOM%;2òñê7¹{CÛBVhx´òÓÚ{»Æt‚ì;KÞæRó(bMƒZŸ ¾¹Ôœ™k+Æåã}øÕ¥›ëÆÇÁ¹º Ë{G»±ÊósñÆjØùWûÞŠ’ƒW:à¿ã}gùÖ´”–‘ž¦‚Ê~y5C¸ýPýrx­X×éw—`SGî|ÉžF0z`Qe¡™ñ/¾¯šô\T Ú _ÿôâF>^c3]ÁL³¹ž€"ɳIàñ~qbT ëL<+E¿' õ.=õ¡êIØÛ”¦ý,ÌGüQoù#–N¯ë9gzWymšQŠ·„â%.:¦Ýô˜è$€3j茮c¼ö4s‹i¯÷7¼eÞÁ»¹w* ًפE\L\¬˜´cÃk\,PmèÓFÉ ¯$:æ…–CL”ˆß¿±i“îs‹Zô•ôð)=õrð6¡Á–˜˜øØ‚Õ9g'äÏ ëI묿GYŠ·¤â:å%ó?èͶù3ºBó¹p»¢âŽUå‹!þ„”‰lj?¬‚Ñ<©˜„a õ—ü>WG‘º ÕÞ ÚÍÌÇ;§;øUw/´jC¬2ã]ôyWƒ“ âRóXb4·!©¹ T7ƒÉL‡‡›óñ>«(GÔa?`Qî<è|sÂÄ«ˆŒù§¹ó2?Üq÷/! N‚´ðœ vFÖ§âUÅFÿÓŸ˜àp¤‡½w7eá1QrT±‘ï—*%¯m.)"å=Å  IÔ𜆢tqáám«“ûhñ4zŸ¸ßfÝÑŸºxáßhÙ9LoᓲE°>˜ÔY/&+ÿ×é¥ý£H }}L•ÛJË6«Ž¡Z1ë°ÙnÕ™ÑG·rÌÃû¤síKr z=`báà-UÖÉÁ¯y* ºîˆž~–j©áaãªK66•C±çVõ &ò¯•‡µ]òð¾6LĺáÉtnWð…#Õ ¯pû§?ü§L™M6 ýÀ«ö>ïyòZö‚ì¦æÆ'”O6Ê~zƺ¿¿ñ¬ÿëđ[8[3û騄¿¿ñ§ÿµÚÐMïC;(Ÿ¾J ;ºgqµÒ{;²šnÜþž‚œ?GÉœNÙ? 1Ñí9Ä ¶äpƒì'¢Sÿþ¹ì>oÅýr¦ùƒB×6]è=lÿòŸþn$í‡Iß›E ;9ã»ØBÀûrÍ’ƒqÔ°†Ðí–é€Ãâ•WŠÓ ×= ÛpÏ ’w-:­ t……Ûºµñà½r©uÊùÊ}×…#:³t¹8[lt[ºWÌÅš­W¡šfàÐ4ñT—e;Óq6»8¯Xþx¹vÉÁðÓß Ùû/x¥'—¬y¬ ³>ò+Ë?Rv,Üù®-\}àjËx ÍVÌùŸå(®-_üHÛµp»?!k–IÆ´m&˜=^²ÊœÌ¶x¬œ—qÒ"ˆä‹Ö‡zï-:(Íù¾·lµ/ŠqËn6O;ÐÐa‰eŽæO§ËW8n«—‰8PqÄ–DÂ+ ôοže¾òW'ÞÌu='ÿ-UêôÞ;e¨o¨âóñ>íqÃkúRjXÃú•Þ3t85¼íÒ-n[Ï˃’ÊMŽÚì=Ã\.ë ¸Þü™CÏtÀ¤kîßœÿYNØPÇk­ïÁ$ßMúÒ»|¦ÚàYñ91zYÏFxYv "q™à¨×ÐÈW‚{Øi{¯é™s~¸òr¤¹‚šÖpn¨Ëõîžâ*7~|y¬â9ï)z²„ÚëàFÿ§z;ð ç—SVý¸åD£ð~N” Äœ<¼}WCð=jXCxbæƒo°+s[õJ:£ž^ñesÿ욊ð­ö oÇk Ø+Š¥å. =P˜ñÛ18ó}ÓúBw]@ôíMù÷÷lH#°Öszhßk„ÂÝè¿Bîøžþ^‡_£áJ,õù‹„Ý  ÑÄ‘/Vß¿À[h÷(ˆWì/öÖ†æcâįâÊoÇE!íc€ýnÒ…iµNÃñŸÒI’eVxHB”0òÛG ×TŽS`jZ“Õü¸P8lš¬Âc€¬ ÏTóª¦'í6£è´M(´@÷Íðö!•/hXµá oÕ3Ô°Fu}¼ñä²±d,lÛnWÊÛ M{ÚKÔwsþf{KȨðϲќ«¬TîêÔÜ<œ;€=?€“Õ`v·ìuj‘Õ?XÅõlMUºDwmTµ›˜èZP=ûö§Ö±Ã{"g ÎúęΘ_s&<ìÝdÜsU¢~ËN‡3¥]Tð&˜OŸ_{ <îÛdŒ“âd—fó‚aÔ…/ ÔÑ]ðí18R ­ÂC<¦Î-{7; ¦¼;5­Iª0ÑÄdÚVEËÑ•^nÂoïÐv3ÒÊ#LL´—«~²PV>WxE¤çW …QÉ*Èü7çªäÈ8UfTbDx ŠŒËTÞ4©2EõHŽÍ€ÌüFyzÁw¦DÅ(%Q‰‘áQJc£3 M<&*39"Qþix›íY45¬I«tž7ebkWkŽ˜€=ß^:¦Gîq¸9Ä~ï‚gÙ(l~QÈIØ« Íw¢`b? ­àd5³»CW]`>àB‡¬“UT$W½Kwmhd „ÒbÈ¢©yÅ?ã½TS ±B:볨™„SQ‰UîÆ?¾•jýóZÀ¹y¹9‹ó?ËYÞP̰ñ ÆcÁÞ*áãÁ­%ÕÞ0_ÁèÁP÷HA¼—À×w@·øÿðŠšÖ¤ýòDJ#=€“Åû…˜ŸŸÒv3òº@¦üý8Hb”?Ûæîüçà¿LÙ;?ÉÌm|U!Œþ·q*Y¿Œ¶”»LþzžÙó ^-©?[=x…]^9ÿù!jçO€‰[óÛkºˆx})÷·ßnÍ Ò¯ k6A?Åú÷NŽ¤ÔºM²^W'{½ŠžŸ†wwÿ¶¬£ê Ò*Ÿä˜ #ëa®þ}„¿žðï÷®uó#°õcvôJÅKùJ¼ÐU°¹í·xÞeJ/EÌwàÔ/0«+ô™ùæ:„÷·QòzÐ9Nn³¿}ݵakÿT¶lÁ²_ ÛÖPÿÐÓ§ÿŒ7¦ËB†ó‡K ÓêOG>$·ïÂwEÙÑ`…QIÓת¸ðƒŠ• 23OD94 ¯ŸÎŽ‘°¿žFV°ƒ±ý•A_ƒ£52Ë>âS^îÁw¾,ï“Iµ(M&‰d†' êgÞý¯°¿œ ;:'Ñv3¬š¡Z¿‡ÍƒÓY¿•g¸|^ÝmùÚïQ|û£õ}-„°KvV|¸•“\o?0tBÑáí–?”Ó­'õ?ø“†@xþ4v %{êäþVí<)ˆBÜz‹ÆÂƒ pö¤k¹^é^=õ‘šz¦º8ØtÙï‹’ýõçê™Å_Ñ6š½U@àêys,|€Çº†sß®ßpÍËIMwD™Î1ÔuçÜàùAMš±¹ËpÑM9ölw–kæ¾¢6Ï3Zø”‡#z6šè Ýgƒdûl£ÍÈöé®NáÐ`óÈimð564¼Çþ¶=o$êNÜÒ¿ë véÎ8«rÓ™«³, @~ÎlΜÃÇ6Ù™d8aó .W°Ô5œq&}ñCíçÀµNñðvÂÌmFº½ø«ù‚ØÓhÊ‹—Ãõ7·šúæj¡VÓýEë›r"c•ŽÑA)„m˜g´è9w†ö¶š3é%´Ý ¢M³¶e!Ù­g¸.Ë!‹â> o»ÜNŠ«576Ùñ ¹Ã~«Wdw»ïõøs–6™€Õû2RNﻥË£¯ïOË'C»9À ‰E‡7¿“ÂÉrb«ÝÇíOï½y¹Ã2øÉöV½K†qCy¹× ð;lu%]|üòõØjV9÷LÕO‚·0t,vÓÙ¤×V‰™/Ä”ùD¼ …T2«@&T²ü¶ YÎÀ>• P)P(ÈA.P*dJ”J¥…R…ÈY5A.SR2$tÑÍÝ`Þ¥êßÛyeJ£R€\‰J Yö6åùÇ ²÷ ¹¢À›äïÌa+S¡P*•ÈT @¡(T ÈÈ-äòÜÏ9<¢(Zm%ÿóäïîüGwç¦DŠ=–òêgêÅ›ÁN6mŸgã­²všºëÎ’ð²‘½ó ¿´áûµ{¸¸#ÐЦµc!u 32:hgdät‘˜ocàC@è/·3ÍIÌi¶ÂÄ®ø%¸FPƶ?ÒÄϾK6­æ‹§2¯c™ùón%^yFÆk-׌Œìÿç¬ÎÁ>=• ì²M,^8é¸I Ãá‘ „´ÆW7Ú¡ìºüàP!Ë&¹Yý$ðV »`ÈŠ è´Ûo³¨ãÎW;(xåÿáôk8^ÙýƒÎ^åJãÕ[.0Úðäê&¶¿[=€8Ó™óªæ¦D6Ý 'Í!D¸¤mûé:5M扎œÒ¢‡(ÿÊ[ÎËw E‰÷áüY‚©ó <€Œ+kÛ.èh„ô—á ÌZ !å6÷+dBÓ½Œ íŒþ½¶Íý ™ìnüÞÁ£·ãfËG[ŸC{¼ÍÍ’÷_â*«,oùÖûž2êpþ,h+¥›^>^qCD ‘kßÌÈ¢)•°ï‡Ýª ©xüê\ÄÕ†X­œ!vé¶ã‡Øµ6<€ü×󠊀»ƒÛ…Áƒ²)È›Xçâ•ÿv¤qܯɮƹ-29xƒúõ68VÒ{Í¥FÓc? ¯Æ¤D ŠIÑ!/QãÜ@L×Ìk#M­e÷*H ñnÄÕ­¸(Ãv9ÌáÙÜÇñ£‹È›®ÌÃû¬LŒ™XÔuÞ¼6&wöX9LÈÆÝ„/Hœ9VÎ-š2n´1‚uÃ…lØC9 V Ó, à „Àœrâju—SiŸ€÷U%ÓU+5)V­høî\ – –kÖþÓÎ/«ü£ðþ•·"ÍÚ•Œuˆœ6ys÷nîë¯Ê¸×lðu®œ¿¢Þ‚ø`ݹú†o¹>ÓÐô%7fͽ"9¯ã”zsCpoµ0¾HñFÕËMý“ÿåí;T \?Ûhs¦Û¨qiK7Ïrøú¸ÙØ«œù£ýù‡-z\B´UÏpMz†n½Å‰ÁCg\ÎÇë¯û›ö+‚:Ì Rj¯éŒ}Ÿ„÷‡ñ3ghTL¯iõÎî­9]ÃöðÃ1sZuëOì¤PAn“…DŽ\¡©¤*…R.¥¤*H% ”dˆ°Ü- ©J¢¥T¥ê7V-ª¼E*…L®R¨¤<úZ$U€L¡+” yΫ*™Jª‚Ü£®|\…RŠT *©²à‡F Ü>²Ú iß¼ÃKðLÅ@5ç6ˆûNÚšŸÑé½ ÷:5u¿/vžþû±».õ½/œÒîä_zÃVrnØ40>oà‘„E¹o¥xKñÞ"R¼¥xKñ–â-d¼Þn<Ê›·KtíÜœµ[z?oI×ôûïûdO›0åm›s6§žÿY›àÂÀ«¼Ÿ˜v·pOŒüâ™;Ê@[›3çc¸{öL’ë™$Û qˆÏ¸#ûÛsa¶öï-÷ë§oHãlmmΞ ãñ™3(n&‘yéT€ëÛÔR¼ÿ€7¾@ñLX%i–7¤øà?ÎÚÜÝ/÷¡_÷÷%¡i׸­r¬:ð¦mÏ=„ÞøÎòSñ*¢òAÄ7ºÕIùÑå“<àí_ˬpR†oœ»¾²gC­IÑx î‘¶\;Òc— ìßð*¢òK5¥éë‡íþŽ7z‹à½cÊ¿ŸûD–tPpøÆ–NÞ/Ú %Tp†¬M“Ã|¬î¥xÿo—üEÓ:»øv,€ïçÂZHÎð€v¦pº¦ìÿT¼aå|ó¯W½UëM>~_bþÁƒ°â#Àå+!ªf«˜:W·€îð¦LÄ¿á-ŸÿÉw{Ê·þÿÕt^”o\U[ ¸Lô0bS°­3v?€$-ÏR¼ÿ€7/«,ÖhluÃÎÍt.ÁscÝ“JE¥ ð@WWÿ-dmže´^¹@wNÎë´5Ü1úØóEcž±µ½/V]fEÍvyiûdÕþŽÞ*#ÔXÏðl6ÞmæÃío³ þ§ãÍË*³×kÝ֨Έ¹©.“ûœ˜7ÝÕ1ÝÙæ‰$.íplÛ SœÔÕ6‰#uUÇ#ÛFŸpZ8Æ®¬ÍH2×·]„ÄÒ@ÏJî2¹Ïóžþ6ÓL#³ñÞž~• mæq¸U;(ÅóSÀû?à-“ÛFüH¯]+ãºCç$žï<Å/fü ÿÓ÷HÁ©|²êh×ÝìêàW Öf'OW= ¼)'q¿aK¶5)Là ºï?â휛ۀj·6£ö©T¼lë z< EUél}À†žRÎÖJƧNHø”Üúáúò«ö(7µ•Å œQ-ë½Ì WA ªö2ݪ:2b¾Ó â+I™®£ü¼1Z¹;+éw%¦e„ ®ΪìÛF+ŒCU3u £ì‘ã5æ¿AH¾™«°«¸_µ¦£êz—hL T1eÜU°~²,sä® Î+O]þÆe· â‘H)ÞÄkêtƒ>§OÜØ=¿îhýjz›aj¿l5•. ™?ñä² ©pwBƒ!Þâã}ëäTŠ•ìˆÐòáa…l¼\ÜÉÁÛa.ŠŸÏ“u¸w}ãÔW^S|»ûéx£­OïÒÚtúx(g:­šI¯¦ÆOàêwRøíxê_sOMo™ï‰cõOéÔé÷W ÖzÃíoT=ÿ$™Í¬:¯_ãy—@Ôõø¥<ëµáTÓé9x[ÏCþãEºõ>sÚæŠ¬À•7œmí…°·ëŽ[,´ëy)Þ¿aË]K)ñR‡ÐM£bãaC'²[B*Ù-pǵ\:éD4›æÒ­bN„ª’=QZ¾<ª•Tîd.Û)2ñÐq.ªŸípGñ°üå|¼mÀ²ÞªÏ©6ÄçÎÏ+ž3?ºûÁ(!\-—@Jý‡Ne…nYN‚dÎÔù÷×Õòçî7ÌÒëÊ-Ÿx±¼ÍQˆuàÆwRˆ C»¡*¯ÓW©Äü~V˜™ÌåZS¥ü§jCzßÜ3™ÛË2* XßW'œ9­`Àx^>:‘ðÍe¦OÉ yÞ€2!¤¶´ïoÇFãX}¤°ï¿âm™;­?›‡ñ×^€¸~ûƒ-§ ÃËîÎLm½$là•bßìPŸ®û&[†^²< îÍÝvH÷dÒ6¹×ãÍGt÷'ïÔYä¾Ig£û’€åægpÕð¢î[,¾ƒ¯™ŽE¢“‹M-Ó³ñ>gS%aÄê¯Idç]otxýïxÓtCsm _“ÓÊ»ÃÇ­Ó{àc¡³!‰Ôõ‹^˜/ðÀo¹ùÙlWUm `¡Ž…?éó–„pÀûïgÓ”âý¯=lE:¿zæ7§yüøÉï‹{ßÚ~ »ýß{ªUÁgáÕÃö1ñýŠ×²÷¾v«´“¢pñ*d2™LöQ][Ž»äwkùXí~]ˆxÝÆ•ÛYXydò#–öïJRqkïÌ"Ã{ÊòÜûàÁÞ}‰¥x ¯ž±±±‘KÂGáM~ýö­WÈ-MÌù_«6|&^K Ú·•Ã[;UÓJodI€9øÓñ¾ñây,¨žÊRõ^ùU׸÷¼þÄþ¶(åêÕKöà ý¦½ÓðÔ¹§9ñ·Å5^U±½§Yq§ã»ÿë»Ûß¾WbâfÛ£…7µ”I+¤-ž¼·Ãßœ¥Œ ú„Û´õy‡\}Ïëu§Ü¥X 6Úoíô‚ô›ãš|ï ›jL4ûaø;Çðú›M5+š”·-Çê›ÆMKL4.â£ðö˜›³ÝÕõMÇ÷~ Æ <>ï*ü¾©HÒÊxÃÐÉÀ®Vª6l‘jN,ú[µ¡f¸T³B<äoÕ†~"i‰‰Ì~Wmø#?«lB5ƒîMt/q´çnŽžqiö‚TÄ;µçз]„ê„öÊtâw?·aÜ#5š³$'cÃÕ9-azýn˜Os¿¡?7'ý¶‹çw;ðvÔì8Û^7q?þ–þœx$ûgo4²âʼ€)ý­­>­©L½ñÿnØâ4¬Ö¨ú7lÊ’Så•}lVYnÚ©Jf9M>z§Løëó(·”÷Žo¾ ›:)©ƒ£Ê¸ÈA4Ó_8r ªx…lSëLvˆNÞîßѕź9ÉŽ‚cRÝ:·Ó;/BÙy*ñl‰ÑP)ªDy@ð µý"nü.T¯‹"ª£eÉÅ[ÚÚPL­ *çÇOš|ò(§ÏUï½ÝÙOv°½! Àůw$åÎÅãöÔ¨¤h=àEù8é¯ *ʤ½ãë¯Âs6 ʼnŸäÌì =g‚ûïÓœ€:GàHU%Sp·âj¿DU>Þrãõ[lR–â-Åû±xÏ=^¿×ñ÷öšý6Ú¨ºÁÖ\¼ÍaØXT—þª?æm|w fŒÑÑñ­!¥œ#îec³*8Œoi}ÌútκŠ.å°®3{fãejä\¼µaj_¸=¹ÁpïW^wö·L)Å[Š÷ÚyóV}>ßÎÝðÐHÿd;šÃðq„ˆ•þ t3´¼“%\« a_3H-çˆGÙ8yÓðöÕÒ¾À½œE]Ë%p¢Ìê =g÷¢þf@£p´6LëKx¡­Fåá/ã†°ÃÆOÀ«zž’é”_Ÿs»æYÎÒR¼ÿCx[ÍÊ}´}(c÷Ä—ÝŸ•µ¸Nzf·¾»Œb:mͪl»"„Uí"ü–"\ßx+Nõñ }9²ó‰è=Ù½ª²ë¿¬mß%gŽl•&l52%rºÏ/Ö¢´Ÿ6 E›~LmŸvdFTðŸ‹sñJ½×EþÝGòŸð*SóÏDRÓ·w;åÿú¼ñ(xÛ!®ïÿÞUÇsYŸeÕ+€“SœŸëM»ò`ÆŒ[1ÛÌœQ`§c«@uYoëîé§7L]újÕÔuÉÜ27½Ëçï˹ð†[LÝîb<õÈÃÙÓ/:M×>±eš»Ûô™îvÓ {N;á8{ú¥ø]f ŽK탰ES_"š7ÿ ÛÿÞðoóÓ"îôasÁ˜#Æ‘7 ~)Þÿ ¼Å¿šæï†ü­qãÇ&È€©ß¾•q½¡Æ ø,Ð7ô†ŽCº¼w<Êst¶gAüRýyv(NžPâcd`ò¬o)Þ´/ªT*•êcþb‡É–ü‘àñMöý;Þh­7¹Ø3û‹lþV¢ÂÊRiÙ*†ŽwA™ÓýSº®™}åÞ£9849¶ÿiZ®W3.Å[Š÷½l`lllp°P¾¶?€7ÕñÙE­ÓÏžf'^¤¶Otê |ít¹¬_6^­pˆ~é<¶3Ô¼•¬jºÔÙE·3þ|Ÿ^Š÷‹À;P®É‡àô~¼‘ûlÖZ}Ä*ˆ[¨]Õ¢SGØ1ìÀf­Wùx£ÆîÕ2öô¨o‘XÙèÈ‘£× _ܺµ¥¢ï—€·_–B®±¡|üÁjC¢VÎ4gÒ·zo»ìòOEöãY’Ê¼ÎÆë«ý·2ÌÚ€"‡ ¶Aêseé–eJñ~x­+õé§¹1 }]áð†æÀìkß<PvÕß'x*Oï> CõDà)s¬r=²]ã4FKxQÿÙ¥®/# ÎÊ;9'žø=ºï€÷Xã½ökl4­ûÁ+ïĈܶ¥a‹o癲8æì”i—äë&, W×Þ¶vò)^¬X°à.\Ÿoz ®-š¿Ø«´ÎûET4;»Þµ´{¸¯Z›Ê 1JsJñ–â-Å[Š·ï‡ñÖNÔ´Ò+É+`*•âU#Þ*¡÷¼³‡;»G–˜ìpä“ñÚœ`CÞ=yú¦©/^.‘YM»»|j´¦à•¯ [!¿•ïíq‰Y>5ˆð¥™{úÚ¢;Ò ¯ßw[hV4-{è=<ô­¦íá?D“²§? ¯CÙ°†[ ›äÍ›¯ˆ)w€·F"UR­­JÁëâÄ›u1^hóx»¾€ï¼÷Ε$ó8j˜ñ-EÍœ")4¼b/·žïVd’<_” x™üQxóf‰”…x4»s©­W2«DYÉ.&R"&CMw‘áAeß'ÞüY"“‚-»…Î ‘)b2qHxžHiDˆH(몊IW$"T£Èr€— oiE|üšñÕ_Ô²Û‚ëpl†é¤EReÓ}}J…úߥBÓ](ÖŽ^³¡\±âÍ_“âªI£þ¦U´&eNÿYDÄdƒy3sôÊL´õÇB|Ùòùâ‘ÌÕÓÃMf®°¯WŠ÷ËÀÛ5?Sp§ £Ï·›þ{÷Åõ÷q|@£±%j4‰-F½ÄÞ5–ØKLÔØÅŽ  Ø{ï{/ €ÒVTÄ (‘Þ{Ù¾û~þ ¨)¿˜ˆ >÷srN†™awfçåp÷Î÷Îl¬+7Ÿ{¥ƒ¸_4¯MýhŽHo^mðóíøiÀµ2¶W†9wœÈÚCG@\¼ôâHß 'B§_H[ªmöhÞÂW»~á¢*ÍÍ; VÙŸÚö¡¦tÒ´š/Ï®çÅÍϲñŽëAzoà\‹éÒ‹9^€NØ(úL/™.””qÿ»>[ó¾Iz._Ô¢M6^ý8x´|Qã®°½â¨SYðàg÷|ìmùhxu¾^Þ‡z{¾Ø8®ò¨!• WÀ¸îÙjÊÙ¼wT/xññ¦{z_Ò;çý4ˆžÖ§†Iã–S®gã%lmÇÚ—sìÖÛï=¢Å+¼êñþ­ðļaÇPëÐP»ƒ].d/ h>Û©Aå‡)'¥ ;¤©>?Îw¨ýýCÆÌ²[ÝóÄ™÷ÓÁ{;¯BÖÓ—[ÙƒÊ47lî¢rupŒtu<ÉñBòmû³¤99‡9;}L¼2ÇÜ~[íÍôÄ[:@~ÞñB–ÂÝî\PîJ/í®yœ{˜rÞÑ)⊣s*Á¶7îŸ{Hâ5Ûóñà$ð~2x ` Ñåa7_ð¦xz{{{F ¼oáÃë5ÇÂÂbîEWàÍ·Páµ=Å&ïÜÒÖO~›Û¡ëTš×*»<7â0eû_¬”¿xÕ«CÂW©!`ÍߌãWéþðα˳î›ÎÕþy¥œÜ\dﯿ¦ú&ÖÝc:ðbky;Õ²R^/ ô§Ñ­ÁŒQWµÛ†šõøox_U•9˜Ôé6£¢Á¬ÄŒ1ßʈ2˜2=çɨçN˜4ú%É‹ô†oPøþÌÄšsMÚžÚT1¯T8g¾Ø3§¯§ksªÂ)ÙRýß×e€»ÙØCw¾ðx ÞתʶÍ`ð1àjC_üG$ëÊÙÀ¡@Ž6s°<ÌNëß嬜•C6Ãánq5`Ú e'¥ÂÛ :&VŠdCÛt*ž Eï?“^Møýãâ78ãðßð¾QUv#¡y àZBÆŽ*039{~æZøm ¤ñ.0¹R$§ ’B9#ݱ^0ÝÇ@ÕÈŠ>b[] ±Ñ´O»ÌR ¼…¯îÄž}5:ï³tÐ1bŸ¬Ãÿºµ¦œ ¤Ù3çóî|3öLë+Ît‘ç¾Öã}ûkM†kÅS£–M¦œ¬¨c\{ð/éGÅ“Äè?Äí³D`oåû¶•¸Ø½ÍnßÿÒlßµoÞ’};ƒt/Ç8ôT’]˜s­âÛ¼+/ŽìëÒ:»0Ëȱžé…rú ²*vt U’TÔ ¸UbÛ¾ß ¸“èm(4xŸz¬Òä`ðªª,³Éý}ÅRàåòvõ.â1­ÑO/³_êt;¦ÞÄûãŒ<¼áågÞT8ItÞ­5z<ô–+÷«½Lûïñ¦º{8êY{¸'ÑÓú}7ýÇfyUe‹[5Ìyòá³&;<†¶x¯A—<¼å5h*¢Ëëx¯¿éáᙀï<ÑUV¨š ¯ªÊ®tRoš °¿i:)kS)oO¤ä‰k‘,\ŸCûá§d$—9–½ö„ÖÐf\+¦ðP3µ÷¡ÙL€3_ä:rìkÆPíî’nE2(¹T/ízS°«Læj6D¾ªÈ4]­íê p¥¤†ËAhš¾VUfØâô¼ƒq,¥óÐ2¡€¿^4g‹¾äÙ÷îôJbÙã$é? I  ºX>%=Rà-TxåŽaÃbÝŽÈ&Ìsš·0ëš4;2ó—á—'HΊ㿞·îâh8Ëyw眘çêí=[ºc >•·ÍR`YÇr=+ö¼™æú7w*uıÛVsº]Þ$mKª¼e¦ µ±±Ó ‹mN:›®ýOx_¯*»X'/—\dû‡?ÑÙ>{‰oc‹K ª<Ñe4^8?”G•wÎÕ´«åªAsD:é9GZ}aèt GÙØê‡ÊšÎ]ŒnÓ §}“R˜+μ… ïÕ‡y±^\Ž@uùÄ ÜÉÚ:„d[Û‡§äŠÛ§Ny“pñ¤MDÞêÇn^=éîþñ]<“‚›Õ©k~Æú¼ÛÉ[OO¸Y¶66 x 4WN\Óâksâšê¿}aË<š;÷rjü ³³¶Ï’ÝþüY^W4ÞÂ…Wý4*Õ›½ÕÿZú¡ðêxëGg©þþ>ŸZ…Vàýð.[¥zÔÝþ°@¹­ÁÑ×¾Ùëõgj4<ø›$»)û‹¹Q÷ÿ#^ùÏAjpïÿFŽ47ƒq¹?ß ÷hàðXã‘öoáÄûêñ­ÐË!ùÇÀõÏ÷Cªû¦ ËZoüØxÝ[lR˜ús÷UúxFçõÔñ¬­æÈ( åòÛœ9ûþÊ‹yÿz’¯h¡Âaà—»\ªòTà-”xóJ"ÓNﯶkqý#O¹w!–ç§oœ¾àfíõ·i.ÙÅ)ÏŸÍë»[ë­/)€[§ýšmÈãåxúv&Äœ³ÏÓw}­>Öö!iû¥-×5bÚRÎF8;f2©âi/·µ}ªýg¼¯J"ŸXMmjÛgä™ …ÓU ø>˜·Ö=ëë:?+ûÈÖwCm\Bl\”Ðo(šË.2ˆ<{æ¡RîäªÓÜ.oè˜J¨ËÙ ¼…o^IdºƒIçãÎ>Ã]:ߨ’öë;£]`tne÷êoÓ\”œ”G$ÜÚpìÞݶ‘ç,&Èu«úÙþ2×Wpßíöƒ—Ðs÷¡žOyÞ¹¼óîú®8·=qðçÄ£Ò.7 ™¿í8Øî*©Ç¥—{k¦~mïC`Û­6?ûý3ÞW%‘ÞvÍÍ­ªîwÈT,‘dÜmsìH—œ:uíjƒsÓfø«y¼ÛƒˆùÒ2Ç Æú EsPzɃ^m»î—/ÔWhÜ¿šv1 À¥Òc·Pâmkôª±Œ~NålaG%ÝÇqó‡H4¢¨¿]©ó„Jü¼LêXã)Ê:.‘UîVicÎKŒ3„'gs£Ú*Ú˜`öm"6êp)_Ñý!ArÆ¡\:kç%onEü3Þp½¼ëhªNÞ/Ú*€+%elû*Ûœr‰§5ƒHùînZÇeKžÁ%=ÂjÞ¦ßPÐ ÓõXŽgp)­€jÇ4gºímÞ‡W»hšÉ7L¦îðÚuùÝF¶> *k ›Bÿ!XÖÉþÍú[‘—:O ¨+{vÔÆµ¨‘‰i+ÇÅS¡Éúœ7¨±ÐQ{X­er;è<ïn͆ßÒI€êÔøéõ:C¤ž'7Ч°ç{ qD£ÖÊÀëkhb 4™ü?v®ykmÇqÙUe!=šþ~=§CÁ®¸‰‰isÜ‹lK) ÆÁÜçc*J_t8–V@ÕƒIÝ_ˆÞ†ÂxæÕh4­ 5-€Ý‚›'6´´zï¡:€\Eý­ÈK^ÀW ä[kØR›[¥4º”¬{%ã¡A.Þ†;L~Ü G«ërñ½Åå÷EJ€KE­a[ˆÔ{ú /øl¯iòxuÍ =/F$YþÚyo£Û½rJ"¹¿¬|΃D+dhtIéÜnÙ=œJÈÐÔ8‘ƒ7LUÑ´YÙx«È:€À[H› ­sÛ¼œïÁ2 Ê:ÃŽÆðËp|º;:‚»Q}·ŸcRÆ ù­!±Í£šì•Øð8Á_äþá]9@É©¥¬¨c¤w€®“YtšÍˆ“BÏÄs¦¬Œ!Iòý¸‚}Õ5ÇpÜ3:¾E›WÊ{êÀ¤ýt~àZö:f×g¼ldKºÁ‹´9Aýg‚“tûµ}8‚¤x¦Ž‡–\* T;öüD<x +ÞNÓs§æ›Ðã<ÀÑ2ƒîßëúãµêžÇi¬ùdkÍîoºÝàpû;‹›FEŸ¸aDå=÷áfÓ÷j¸ÔÇ|s½Ÿrî/š±pŠù´`ÒgM12IäjÓj.—ª7¹~fÈlà /åõÈ$aÔ€õªŸ‰Ÿÿ¹ùóÉ%Wfø´¿ÏÁ³L‡ßÿg¼aŸçŽuVÿäáÝ&Hiʵ!³ÆåÞ„Ìõw3ãSûÿša\n‰â|É]óûåäõìÕó>Ÿ?ÃxÆœ¸ÔQ¥—'±´ët8ñ»À[Xñ¦äAIÏ"Y •‘—œ“)a èââ¢Ò >R¥Dž¨Œ‹Ó‘–‘•[ªHt˜ ÐEEh -&6%56&”°%(Ãe€*2.=6I#‹NˆÑ©…ÌððŒ·èçÕ&ä^)Ó%k•)šèø( ©a¯v)=,žÌÈXMB\´Îù‹ÌðxHŒ‰IÖÅ&D*ÑF†«ÑDÇG©ÑF'ÊL·°â-€ÉÇÚ†Ì}R¨.?·MàýñÆ:zôè!WÝGÄràèÑ£¾1ÏÃtܦ WàýŸI½ríÚµ+žoìåk×®] z¿Ÿ«À+š ÿ ïÖ´m‹ÞŠ72ÿdÐùÿṑh=ÝãÞXñökw8CçãþO6Sxx¤þg¼ªLŸZP2½vWa«ààU¿Véj`¡næªö®x5õùr[^ÿùùà^§íZqýßnÈÃZÈ<)9þW¼Úc æœ,8%l¼}ç¾"ÚùþËV€ìÏ¥Û ßüÛ} ö?6ßð·bW €Òçÿ+^÷ïð¶š’û}g†AE£ž?LuàÈï\;÷‚Ñ*Ä­6™å ¡þvåÚÁžYKG£;8uïâú¾Åd¾Ä/6µo˜ƒ7ÐtÔù¦Á×M–¥Câ:“¥ÏŸ~ä_ìÙ2Ñ‚çN_ì)ðŠäÞ¼ª2MâÆß“¬NÌ"ù³ÓÈ–ñ¬·Ô¾[/·}Iý­ºÉQ÷PògoûÀ Î‘ŸâÐ!F9Ø8ñb‰œÕEiO⨺á-–‘1xuÊÞn‰GËÆf‚ü‹ÉIê$ÒriÊVWäÝñê}}› óõÉy ú´]twÔemas-}‡cûƒn§R+ŠRç ’i°VÖæQ…ë~~•O–{¶Vn³ÁC ãÈ ºãú­‡Ÿ÷—WΗӊÖø ¤Þï”WäÝñj×Î_X¹Ù¹Îíi4eKõU§ß¬*Ûùç’È2°³Wôç.\höàn±tø1÷ Ûý¢ñ©ã:qús‹… Íž;”SòÒÎK<R»‡“NàÉ—fCÞýyŸhì¶°û¯7ñž®­¯TêoE^Ú™'R µšÚx”O ø§_†Bí yxã²ñvær%5ø¦Ù•Ó¥¼´AR€6šˆe%^¼"ù‚·ÙÄÜ)˾ŒÝ ùùqµzeM•ª{?UR÷½Y®ý߯QkÛÍ‘­•¼´Û:D†µúA‘õ»i¦ïÀE?ó¬Ëú+³ÇÂkoHaêÝåªa­”i}-²ÜI¼T6`‰N—RôŒæ™ä©h磭À+Rèðj³²²²²âÌ+ò‘ðÆEò2 t¡™ù¿A1q¤=~®xEÞÞ ê–n jwõ ÒLÂÿÝÛŸÜe’œ7Çp‘ ôß(¬dÁCWäð²xõ§¿‹{x« íŒH~5äüí2º €ŸŸ7Gž ^E“ÞX«”µÀ+òx[æU•ÍœXqZßZÆŽ3xÄåIK.Mߨ@wÚd®MüB½‘ÛepqÎô}*â–¾ºqÚ3ÀeÎ̱.6Û“ÛØ^;cž/\©_u–ÑFz÷qcÊ×9ã]Çï‡ûÅ\,fùqiÜFœÆž`{‰ÞËcáο ã;xëG{¿V‘Aßaà!¡lº™  ýøú0Ø(ÞifffÓö‹ª2‘‡W’’’’’?=¯À+š "ÿðÞ¹ÆÙ7g8¾¾Tà)Hx}^¾ú¥_×Èê=zóuÎæMn\*ðŠ(¼Ír/Rh3šݻÕ*B¡ËT!“C¦´ )”ZE–Z£M¦šL%€<]#ðŠ|d¼yo1TÕ´isCGù²ïÖmêµîâüîˆèÝ™u~šÐã¡óÑ„W>`ÑÕõáß§õxE>.Þvy²b»1ƒ”žÉýli¤d_uXß!ÈÂÆtƒPé0ki#?»Á~›÷µíw^÷ñêÎ?Q«Û‰£W²—Ž9 íôP–²#TzÎ¥’™XÖÕÀÖÀèŸ!PòÇ©Œ2¹Y«÷¶í6ßËÄxÿ ïÍ‹—ëõ»ìò`ÓäªCF3i%(ËØ¢çËżØJyxq.-#iK‡ú;tïiÛ–ðPà}‹fCÛi9Ê+íÒ¶ŒR(A[Ɖp½@®”T°·ÄÏ[Ò<Æö€)—Қě°ª\Ö{ÚöRÕSZqÞÄÛh\îÔÒAôܨJkâ%ÛøÍ’{²io¿Q{Íú‡$uªïŸe'9$mùµ<Çpìûêo¸#IE†‹c(ðþÞ³·r§n¹cÈìv<³Û:ðÈî³áûw;\Ùáš|hÇÝ—––W“Žï9óòÈî³™ïq¿·/lÅ%IúîˆNE·Ð]¾S®ˆ$IEF…ˆÃ(ðºÚ†ªm$I’¤*gÄqx Þº«$I’¤·Åqxÿ„·o>¾“"ß·Ý£îr’$õK‡QàýÞµo¸çSîy̳wÏßÜßU5©µT±G=oqÞ?á=[­I³¦ù“fMŠ~Õ¢i¾¦YÃöºMî*gÖÇQàý#^ERB|>%ñ|‘V‘ñù›„¢cA>¨»¨qxÿˆ7?³XúòÉ{ڇȺ Äxß^YIZó¾vâvEñŒu÷ýáu..IÍUïk/¶Wz*¥Àû¾ðN‘$éóïk/tÆM“ıxßÞøÚ’$Ifïm7Ò:(ÅÁxß ^=I’¤†‰ïm?‚¾[*¦Àû^ð—$I’¤ ïoG\+GSà}xÕûV-¯ñ˺•wÞ㞪(JÞ÷ò… eÇ÷Ü¥›ÿ}€8žïûÀ›ÔÚö=ïŠzxGQ¢#ð¾¼±Í.¾ï}Im;D%ލÀ›ÿx#Þzï;Ts‘8¢oþã ©óøýïÛ7–â ¼ùŽ7 †ßØnŠc*ðæ÷=¯ñ!ögÃw>â  ¼ùœ'ß$~ˆýÑ6‰GUàÍßxTIù ;”Ù£{¦8¬o¾æöwéf¢šÓˆã*ðæg®ÕøP'DŸjKÅqxó3çë°û‘^¯xPX7s¶©üƒíÔ±Š—Å‘xó/§Ú|Àjñµ•Ű 7ÿrð§Xw 1k%Ž­À›_ÙÕSýwKÞ«–8¸o>eÓÀzó˜†ÅÁxó)«†~Ø›@?®¶N]7²hÌÞ³‹Ž‹Ã+ðæKfð?ãûªÞÇWàÍLŸ–ïÛ¶xæÿÊìje§Íü˜1Ÿ³Oû$ðNš•ïÛî¦odnö÷1Ÿ3Óì£fnׯØ'wÌÂüÇû¼`¸§› `ŸÞ!+òï÷¼øñt3ì“ÀÛoÃ{À[Ào*m-ð~x»ïxE )Þöû^‘BзűW¹µ“Ýß/MØiflr(M½½óο^AvÜÜxÞe°ê1íÄ?vküeïÿ¼?Z„3¯¶ææ¿]Ñç„Bs¯æ´uMÿr…¬QË“4#· Ú5ç ØË?~zÒC÷ÓÇ«kh÷añÊîº>SRo(ž^yª’o^Ñêê [0 `÷hla×o¦ºÇWŸÊ ÌÕ-ŽeÀã†>Œìýòj øbüEi£D³á“Ç{µićśïy´Í³Ê¿|š‘Àûiàµo‘XÈñÆ-wT#ðþÄ{¼Mf!Çû"ð~xw·ËÿûŽºÕPì×Fàý$ðnù)ÿ·Ýí[Ç+97´À>*Þ›ƒ‡Þ=‡ûý¯rèÍ’Ä»ÅýXÓ¬Zkì£âõüªA×.ïžî?¿ûkt-;âÍ3ïwáI9ÉD³áãâ}Ú(¤Àl¬ÉïøÂ&+Øî÷cã ,0;m˜èmx^WàxÞ|ůTÅý‹—M IøÛeI/_ÈÕ!!AA™þ"MœÙˈ ™À[ØðÊmöýÝ«]¶xþĬ¬ØÛÏò¼Úkïü2'Þ†Wõø³C÷j¾c¤s¤A¯ÿVÌôos'w%û¼ùçF;¹|›î9GyÄÇ eµõx;¼/[¾*ü¹Ù-³ÿ͇°åïï)Öe"@™‹0é7øÙöÙ Û= ÒQ·0áÕ*4@¥c€"û…@‘3†vC«Î™9뫹€&çê­R{°&j ¨u .åLί?iâ 8·ŠÅ°½Nä<µB©Ê~e-$ê]PêÞ¯¯”ûçÀ~v׆ õ·H%rõœ±—LŽà`â&ß`ryûÜ›€›…ÅM<ç/x²Ê8 §… m²XÛ Ü–Î>¥õ±9+î‚û‚…dzºŽ”eìaG°è,gþþ(Óà[·0á½nhd°UͷLj˜j4|·ݹáFðbÊ”)Ù7HXu¸Ò)8»¥8N42 ƒŒ™c7O«ƒ]ËiX7<м”3$Ì5žp“YÍ-1¬ÈhŒ§êÚ@êâ©“,U8L6k•¶´ÈÀ©oƒ×_ÿEÎT´gË5oûªTùšïŒëø3Ñ•Öi|ôúxÚ7½K÷;·»]LÝ/mòŸü`Ó §w;ر¶Š¡¶]wÀŠöÏ{ã[ÓîÙ€{¯á½£ÇÂíj/â,N7Nö_¥x Þ'?Þ³o,ßÃc9qÕoVƆSÕ™Ôq,w7i.—ONhfÆÝ†žXô“±°¿"k`øµÔÛ„¼”3Š +Hiu¥›! ™ZÞ¥]Ó©¼­©ŠŽ'Ýš<ãêp¹¼øÍ·h6(“îë?JJÌ~Ò[J›Ø{]¬òÓ“SÂÚoBSê ˜Œ ýê´´ù¹®FfpåkpË“µÍÐd¤­h£k>×ysW:® K~…·ü@óâ ³šË•# Õï8žBà-\xç·^*ùöxÙœ­¸Ÿ¬Ví­^ÂÊò«fõ^~7°¢ãÅ41ô3ø– ¦ÆØö=ü6lA^Ê™ð/7ØœmhÜ+ïd&·€€2>T;@ê׋m϶>u hBµéÅ]߯·‘¹Þxsãg@ÒéMÕ¬&µ± ÇŸêŽ}Æ~ÐhŠÒN°¡)ßô77Ÿ²ˆ«ÅÓÁW/ûËãÚfd­ÿݬscY¿£R¹¾u£…1¯ð~q8rqËT`ŒÉÖ{tYµã‘À[ÈðNi—ýÿoqªÝ!‡¯÷A⦠¶jqRkpÀò›7L3Ætƒ0½ç”·½5á×Wxƒôö88¸øš ·ØÁävõÙcª ±Øz—g³¯¿^à¥~Îxœ”s¿ ql4Û.­BýРzÖ°¾P3Ê’6°øgj]W?OƒÒÞÏÚf\+ξºAЮRŽ*’/·êÿZ³ÁyÇõÀ± 3ãØôãô,·áÝÑTŽÊ&•oOÒ}(|·ŸL7Øñy²›–_Xé†O©¹ðãLÖµVs³Rm×Á’š0¬Šïw *åBüWáν§ƒ+-£™ZOÍíJ!T;@VC+xtwIW-i¶ÊŒÏn'¥ý»/l ´Mk$ôLÁá›Ì…-䥶¢ür²2¦õÖõJÖ­ÞŒkÑ P 5ÓfŒ8Ïš&Ü(é«PF]%½šý5˜Õ9¯º„X×M¯Ï ྾o!Û6xÕãM“2}‹-N\Ó膳471¾…Ë“ýµc–; ^¥Å±å¥;­*jÖ»~¹ÈŒð'ÒædÝáÞw\{c5Æõ±íÐDöûìô£þs5T;6]®Þâßk×c‹¥jEí5«ž¿ Þõs»å¿>þ]¨WM5špè±lûõ¾¤)·tíÈ5j›'LÛ”ùÜ þ”@ˆ_l4õ˜Æ±oóýòµVLm¾‡IÆã·È£L§N ÈÅ?¯Ád¿ ÷@1ø8$ ¸(ðºÞ†Ì3;meJ«-;}uç¶¹Úá˃»¬R‰°ÚµÇÀu뮀Êjë¶Û$ßå pw»ãÝ-ö*­ýΧÖÛožÚjn»¾첊†;[lÝvžÓ@µýÀË}tbçy5<ÙrIû6xÿ2ÚìÑÐé´e.¡Í›«Ó¡Ñh´ýŸ.ûh´šœ‡«uhÐiíëAÔªÊx S?ï{Í Wm¥Óÿsw¨mß”–Åÿ‡šßoÎ__O¼lüÓUWàÍIȨ‰ï o¦íá£aúÃxÿßà%9\É¿Ã[ÀŸì.žô±ñ6-0kú¼ßE$èx?.^ÏzöOŒ<úæ¶»Ÿ}W£ §f91óãâõ®\çÇ&#ÍÊ}óÌ[ùÖÃUͰ{æ­#<´`$jÌð7ñÖPì×V4>ö¶fc§‹a@"´·á#ư‰¼¯À[Pñf¨µé€:¯XŸüÍcU–À+ð0¼)í‚oöÒ•n¹w¦ÌÚXá/FKÚ Í騷{ïŒS©¯Àû^ð†u{…ðN¶Ïä>¯*iªüÅ ÑL@ºòvï-…¼ï{Áûªž÷Ö®¡Í÷wµ?3óÐIîïp|dy¨jyÁÒ:¸ï11÷Üúä -²SŦYefoy<îì8ÿp—+uv÷‰@È<³ûBΠД­zKu>–'ƒnK#ùänWÀu÷ÉDWà}W¼~úÁ9S!wZn¼ð½‹‡R¹ê3MxŸÒ×jŸ…ï‡xZ4æQwû«=ÓK‹?¿°"ª‡ŸoöTrj¼ûìÞ)„v/wÓîgÒ‡/sߨ%%kø:wÃÙzåçõ¬}tq‹¤Ý݃û[Þ¹M½bÌýýã^÷]ðj²dOõŸË²²›¸©m#=~8WVq=  ¡ò¢ŠÝgÐ\•jS3žKIWªª’—€¨(uD wßLGK3v5‘¡<¥ØÛ$Eýì Ÿì÷× ¬K$§^Ñ)S}½êíjÔ™õ7¼ï»àõ24£g`jè ¤:ï©î0½½c(Ø–Ucغ@•Ã$½C½®3L'Lâ©~$°¯:ÈJ^<ÇMª º@›©¹ƒõL+˜™šôóÏ9¡ëù'*ê€ß™™µÓŸj:càaWà}Çfà ýðì‰Ä¿ °j0íXàkxÇA•C$½C³í@8Oõ#rñ–pAG3 ”Å^á׈×Z4¢sîH"ùëtœøZ LêDß+©ñ¯Àû®m^)·ÍËà3²¶þö_ÀÔÖÐeb%»;Ť ÏÅÓÁJãÓ-$®Ý!ÍönIº i»fq M|Y'6×vœ ÑÁÞã©›„¶gÝÄà*.$»ªkp4xÞ·ÄåúQ½“ׯd? 0¦EÆÅ>S˜ÓºL€J{ˆÿì.&ß¼1»:žÒ tºWUemŒnÞ0«Eë p¨\Þ35Uà£:[]FrEWB$/.”–%}?øNœŠN²<]­‹øCÏß Æ>ÒŠ]~j}!*Sàxßoèþ#kô69„ÏõíœN Mïåàm›SU–]ùƒÁÑ#ÇÿTùý„£G;óý^8“ÛæÝ]€UAý¥!z~\,™IàÌú­Ïäà]5àÐF=?è5jìÉÁ»¼Eƒu*Wà}ëfC¨~tN¯XØøY/Û Í»²Z¦¶®ã¡Êa’ŠÞ¥ÇJH¿Š§~°¿:ÈJ\ÎȤëZH»J×¥`Y.çjeÀµ4—ªäF¨ž—JÊÒýHŸ[A×i’6 E)[bõü¡÷H¨±—´Ïn§gi½Ö{&ðd¼ñ¦i®+€ë«òfÝ8Aó§õtó£MÔ¼ÝÖ¨uÿ¯”»™ºö.!¢µe‘ˆä!uSÓ~Wfm–ŸtVq­Õõ03KåEÉ]†je¹X­²úŽí¹Òêf¨É>œšÞóïV**ûÔ›1xM¸Ý Ô¬_‡Ï%SÝ“nÊŽI¡-žFXtÓ ëçhƒ¦ã¤ˆÍÒMUJëžéÉå—gfUÞ»å¹¶íµˆ#uÃÞ‚†7ú„*oúZsÌ€;¯ÆÁ(ö—ü ¤KŸ]Âçí¶Æ½LêÄ=.w0™bqŒïJ€äYãÖÙŽ¿pyüdç]ãfxn3˜Ìí9³l‰\``êM´É¸­Y\4Ü«„[sfL¶ž·!çUS·˜­Š€ÄMfÛÒ‰]b°úÙ|ƒMɶóÍÖÆâ;cE¼˜5çØ„E1öã'Þ¶7í!ç§TqÅÂ|Ñ3Ñæ-px/I¹¶B½ûût^ã«“&¢ôÊ ÔÀ™ ©Ï¢b½CHñ “ùø©"¢ê’]°²ü½Ó@ᜤd¾Ï€`ïÜ!¸'ŠÜE˜á‹.àY*@€wÊ?ã-x ^×Ïs+u|VÕQ†ßÎY¥ìÖˆÄEoï°NÍ™ÒG涺.#æ=àõû»WÔó´ýüLú"iÂ^*“)Ó='n±ÞŠ­í6k Ÿd6§ïUݺ‰ó‡ç\å ž¬?ã$ò½e'îùe¤zñÔÙ£|/3œ3ÒûƒâÕj´Z­V'ð~Rxï~žwõ)¹C´[_€½u@St._Åq¦ˆCúÒðéu}îHwxMÅS$ê²}0òWéíãlÅí°™°íÄévZìÚ¥g¿ê£Ï5&#»µógØÙƒÝ`o7å‡Ä»ÎØÄdúì0÷ÓÁë>cÞð¢fófEêô+-Ó–LÏPÃöºöÙu<õÃ9]VÃÔV\ø|ö¼Ï]/!´N®çðÐb^³V¯ïÎý¢ ¥¯J=¦Æ‚y“+Dæpü, ê>àçF æúNÛ¯Á‚ycª¤‰fƒÈ;àM zq¢¸×‹`à=µmSój¦zåà-–ƒ·¼š©­p.ã÷"$<ë|iÙx×<ùb|3ˆ/âÎý¢ é%o íþòEh˜ê ¼Õ†‡¼ §ÛaᚃWs7-ížæþéW]¿ð·$‹}òçyÎ7þ¡½ðÜé¡À[› ×?ÏÓò«}FÛP€=õAYì.~úñØÓÛàWó, ¹Q€Šv„KA÷’°+©ebsH/ò„§EÓu½—ñ³û[da‘Ólp+’uCß–tÑò|9«:ið[ªø'¼Ú”Wõ4QuÃ:ëàJ×ÜÎåÅâûÿ¼ï¶@9òñóBKýmaŽÖàð´mk·⽜×ÛW7Ä¥ƒHþååTkiIÄVé÷4ý«A¿½ËîAÇÖÏ}9S:·‹LöKkm6#–vÆ6¿uK?&­‰X+Ë|2`羑¾ÊI¦ÇL¬rÎv!?,™-W»–sG.86ʼnäÑsMµÿÇ/le^U•9ôd¹Àk «ù+ ’\ÞœçPþï«Ê>·˜Ú^à-„x“o妕?ÐÄ<H½âz?Ãíú¸Û×Ý‚]¯?Џêê ¾.nÚ¸«×/¦€×µ+¡Dº¼¢/ß{æê•uûú͸[×oˈ¿z9Ôw]^õ¸Ä yxíÒS@qË%PÞv ü箲תʦ6m6½úÀ©)“ã0pÚ¹ 3¡ÚŠ]ÃOiÑÙN3Þ£zaÜëüâ>çÆ¾²h¿eÉèÎL3Ú§F»güÆU9…9Êí½öîyÈoň  96ÍøxÖ†b½ÇÃäg',Ê"sãdÓ½:·°àýØù_÷mÐϽoƒ*­‹C`ƒ0¹Nw²„Z=¡´OxP}húé*Áœí‘:h³ö¾´V¶ëÁžJèRKÚ+tœé•<`;'[¾Høå›œ3¯²N¯”Ë_ÎÍÜùCûú%Æô<®,{J¡ï|Ãk[²¦NjTï WàM»sïÞ½;Aÿo’Û=k}Û{nIÙßÃZ¦_î ¯ªÊ~š•,‰/vÎFîó¿ÇS B«}U˜Ó~ºÇýÙµi·æV•Qo-òbvø ¦ÁÂû÷§´¡œ À¤Ði JïMÍ—èÝû÷ïß}S÷ßð¾´Ü¿Boõ~ËP bŽÁ7óº6œéþ×Ue£ì?hó窲±´{³ªŒúÛ•º@€¤+o|àÀgmÞÐi"ʽkŽ x 4ÞÆQùð6ò|Žaö?[U&00õoeé—ve5Lm“‡7©è]º­Ù-<õ#É«*ËÊ¢óFÝæ§°·œî^y© JÁ49©÷´eÏÊ3ar{è4‰­òI%s· ãõ¬ØwÊäwÎvùð"S¾ÿ_UeymŽNÂGšýEãÒ‡×ÏÌlþkFÊ—›Á’“êRË»±³¶«¯IO¨×}•¬SVÝ»û1Z¹Ç˜Yr¶é“o•Zu‰,Z:!¿/yh¬Ú{FL=E­-î‘9´QfæC²Œ,šnx 2Þ¨¹ã'¾s&×~{÷W™8áÄßâ›{’Ÿõ|‘Hš1lÍøç/Žë¸c¸ñÓÍ¿Ï ÂÕÜü”6bÎïÆ^DM¾9 Çñ;åpÅÜÌZ §6[ _— >4|ÊíÃf>\ö»EN3fž…‹¶eqiìˆ .#Æ\ \i>ÃJ+ðd¼ù“–’uþo»¸<,ð~¼7KH}µ¯H!Ä«[(I_û¼ëŒML¦‰ª2€ä:’$í*4xu:N—7}x?¼.’$IÝÕ¢Ù RøðŽ•$I*ñìCáU, Z®ïÿº­‘œÛý§ Ûg™_xÿÿá¨!I’$-|ŸxÓÏeæMû7L=Öxlþ¯ñ^«,N®ûÓ‚ƒ¿†º58%ðþ¿Ãë\¾lÉ¢_–í‘õñ¾úžøbC×°I³_jÔÑ™ ‹ IË[IÉá±Y‰áq§bBÒÑDÄ(£Ã4ÈŽ k!œ¿Ä_z„ÕÕœöìÈðó¼¹lrÇ¡qÏ N­²8ûc:eÌPöXÇR¦­`‹tfWsüózŒ’×¶òxÿ?â=Õ5ë=âõ™³hªÞ´Es}êYã¤#ýZ°-«MéØÄ"wÈYJÙÑ‹—4¾Ü£ûiL®¾dÑôR!ÚÒö°ºKfF­¡×X¸Q:…}U`d`é¢8ñ…MàÍw¼©O½ôÏ{=MÂŒzÔ2­ßfŠ[vIdÖ©AµVd÷Ù&}~ÄËË/üËÏÐñû@F·æõ<@¡*íëZ¼†·ëxp+žÄ¾ïrðn @àxßG³!Pÿeîä”mšÎ×Êìë*f÷0+;m+” ~tƲe&1k{šËHZ–ª.µFMÇ¥„殓¶°¤«–­®czƒ6\.ð ¼ï¹·AÙÔͳa5[ºô¸Ë1Ûá‹r×ÿyÿ‰Q>/L'j&VuNŸ4ßvÆ.]–ÁLÛY´ÊòÃ×uÆ»ÚÆ9êøŸ*ÝÖÆ ^{¢÷M^N,q?¸ÅO‰lùRàxß Þ ÇÜ~^õõ¬¸ÛYŽö3}ímîå]é}yÖ!Ž6—å×Î^Ѩ]ÏÜ”Wm€ò‹3×í"@÷èLqgÏÝÒ’qÞ.BÎÚ»=û¹[–À+ð¾¼ïm ç÷ðá ¼ï;ãMö|öì™WìÿXaqឯÀ[ñ>šmaa1÷ê߯ S¡Ñ ¼ïÄ[C]°?ܳ¯ÀûwxKî?Yc=©¡&ðþu¼ÛtèXÓ©íLàý›.¹¬€G)€ ¼""¯ˆÀ+ðм""¯ˆÀ+ðŠ¼¯ˆÀ+""ðŠ¼¯ˆÀ+""ðŠ¼¯ˆÀ+ðм""¯ˆÀ+ðм""¯ˆÀ+ðŠ¼¯ˆÀ+""ðŠ¼¯ˆÀ+""ðŠˆ¼"¯À+"ð~œ\3¼ dØÈEZRàýwY_eÕšÕ?†US ”ï¿Ëºß Æv\®£(Þ‰÷B]Wàx^Wàx?¼Z¹ö-“˯À[@ñMú>êï–U3˜>r½\àx f³ÁG ÿÛe1’/1 · ¼oAÛ`êFžúáröäs÷(\N\Íþ¼Âõ¼`X{§3.ÇC9m WO]Jr>zßÊ.5挭Làx?Þà>;œ~_ˆ§~8²¡Û·u†]?9lÊÄñN“-rð¡noè$M»:öð“ŸOîì­ڃҧÌt¯fœ‘8t½Bàx?ÞñSÀk?žúá(]abwèÝN†¶ì2âÏçà]ºß|Ptªt†”ˆÞËa‚1Ühxp‘æ 'kê?~›xÞ÷·¶%žúᨬÆOoÔn¶nfà©ÛS¿Ý¢È¼ÇÜɉѪ2N°éG`y™'€oÍ—vŠ6¯ÀûQð6Ýd·y]Ë?Ó™5Ô×g”¿E²ý€š±Ùx}€l¼ÊolaM;Ðn©>Ð Y°ÈGàx? Þõ}äX-"@/ÇR©üÖŒüPW8h¨Æý³ €D) UÏtFãQôÚW6z5¸ 8–6Ö ¼ïGÁ›µd²Ùô“KÎŽMžÐwm—jÇÙ1Ò|üÜ„SÌFlW/¦—q–áñÓ&-”q¢ñŽ˜õí!­¥¯ÀûQðB\¤eLr¬ML|VB$GÆêÐÄE& ŒIŽÊulrT& ‰Ž’ãRU q©1%Sàx?ÞwÉC ð ¼…o€á¦tWà-”xß2¯Àûïñ)ÛqYàxÿm64?\r¬žÃ&ðþËlþªgAHï¦õ^÷ß6© DE³Aà-¬_Ø\^Wô6¼¯À+𠼯Àûñ†…ã—‘oæî– }|ÿÞí›! yvû±Jàxó¯úµÊÅ_·¤5öÉ¿·™XåPˆæÜWCméd‹úÒ\)Vàxóo»Ãy“í·ËÇû6NîÐxl¯«ï¢q¯À›ŸxkæŽÖya2âÓÎõ¦.rqÝä'àc1Í"Ý¡áÛ­&Ú4é pÉ|†5Ú#ƳNè.›yÆtq<+3£Zàé<ÓÅ^$¬5Y–=^~r;€†[àBIÜxÞüÅûÃîœ U‚ÅĤŸv%(´ÁÒ̤ùm3Ù°%yA?9i­ê…]úÆ8zßœïâÚç¤}­ÐஉY«$ûãÁòä!þM€{Ëë Ë Ò~]›¼«Gêkx·£3é¯xÞ|Å« ðóûn±ŸOö€JFYÑÙHÑ»Œ{ñ’^ú9 ‡NáÂ.b?ó ‹y`àâÇKÚ$EhÙQUCð×u¡!ýûÁàQòÐ¥Ê#¯2ίð6kgÒcH,¯À›¯xË,(×sá,+ëÝ?˜¯ý~ƒ=$½Ã£"Ñ0wŠ &Á·ÇH(âN­¾ Î[ŸµºUýEql¯%¯%Ž[P¯74p¢Ä¢ ͼ^;ó®—Ÿ«å-ð ¼ùßl¨“;äÁs[³ûÓÝIEÝxX$VVê,az¡Ði"|{”ø"î´Û Ï8ÒnVžÁöj:^Vð±ú&vƒcAîçTU >ño¶y'þ.ð ¼ù·ÚöÜ©Õ#ùõ( ‹’®jܤPe½%²m’¿NÙr¤ZQv¯:Bº¡=Ûòyæüƒ[)Z.cW±+²™}•Î_?mÐYÉÍf²U “z-‘Ýý%&¯NQkµÏJ×T¯À›ßxÇ:äN­?©6ô’–ülþlN÷E©Æ˜oýy^¬Uß_]w÷œà¾ºûô@쌦ïSÏ7™ºSÆŽš6Óg„¡Ú:zÃôþÖpÛÌxs:‹Œ<Ïëm¯ë=ü$ºÅ¿]ÄCàxóï;dO½ÿ½|\£ø×îø”zA\¤x Þg#¾¸¥ù_+9óiÞÊ}FÓ^·`à ¼pñÁ»]xÞÕlxç¼o¾áŽ!äm7]ëûÐWÿøÙÞ TÏè^÷#â²%½éÛV•¥}6ýœÖg†´u÷”áI2›‰_*^÷ãírà?­‡uûÙËÜ^·Êñþ¯‘IÎ?.:^_àxk ^ù¤Y?éW|/Ü8sŽZàxkÞ¿"¯À[cñŠ)NÞ?÷Ã8Ž+¯Àûg³µ¥•!Äv¸X“Bàý³ÙòÑ|CÈ¢Q¯Àû§» b)+W\°‰ÑWàx^Wàx^Wàx+ ï£\Wà­¡x›íxÞŠ·ÕžòFÞ%OOOOO÷Tî_òôôôô¸ªQx–mŠx^CÄÛú`y#çÄÉ“'Ož<ö˜›e­3š’Se›~x^Cë:ëìüÞ gÇÛ¢Û ðÖ4¼j¯K—›\¾p ÞÔÊÊÊÊjnGÊZ‹Tù6VVVVVÆ.¯Àk݆ýå MqYÔ(Ë%èÊ7• ¼¯!âm´]Œ6¼5ïñ0Wà­¡x«3¯À+𠼯À+𠼯À[ÕxoßÕ]ÊxÞš‚7áé‡× ú9·u¬À+ðÖ¼í® «Nü<Ö³gQÅÒjZ¿gÖVѹ弯¡áÕW•=6ú¡eÇ/æ»ã›>·I»êããããs½ÙÝMýŠ^× ð¶> o®ZÀ€"— Ÿ›yAÔA‡Ã¹¶ÅÈhM”Vàx ¯ÊÝÍ­Ñ·³å%£Üä_Ç…-ÞÙ”÷Û½T}ëx^Á{á¬k£Ù®.AkMOœÜÄx”î8ôÇ pÛÄÆÆÆÆÆ"È?3ÕhÎCWà5ÀnƒìT/éÒ¹ù…ÊëÆ]¿?™‡2/?????OCÀÂîÃv¦‹>¯ÀkHxŸV•ÍŸŽÑýö4çÑ^ÏŒ6LZªûËCàx_ïÚ›­×Õ›RŸ}™æÚ¯Àkx«3¯À+𠼯À+𠼯À+ðмÿ%ÞÍÇÔæ1¯À[Sð:†ë›Ú¾RÛ‰z^·ÆàÕߤ( 8×êò¦Ïý²^·†àÕ—Dfîßýplj?G#_¾ØÞÞÞÞΙ yööööö R^×ñ¶9¨o.ÚÈ€«€&.66666:“‚èØØØØØ…À+ð^…½­Ýýì,HsŒN<úân>èò¤R©Tú¤å©T*•JÕ¯Àk`xuÙYY-6de¬›ÔØ|h+«P²hž­­­­Å Ìlmmmm­R^×û¼?W´\‡±dM•‡À+ð¾ÞwV´Lçiº]«)xñ9~2Aà}1¼úǂ㳵‘òš‚×ì__÷¬ÙùºËŸ{¨Jàý-ÞêÌ à;¹Æ÷4}÷ ¼ÿH¼Æ“j<ÞRWàx^Wà­Éx‹ É+xÿÑxO÷ÓÔL¼Ó¶Ê{„×D¼qGœþŸ›€îGŽþê·ÖçÐS º[G¡Ðåp—w^ ì‡gàûWBˆô¬^¼ ø?ePûWûüŸs½ŠñŽ>ûôÛìþ¨«¦&âÍ\'ùã‰ÔÂ&õ=7àûg_ ‹l<«¢]h¹ÊçúâùJù ‰·‡=T§Ç²ó’ePæêW¼]kòûrøkOªoL“ÅûÿÇ<¼ÿNÓƒUŒ·YÅMФůï-ÖfÁ=P—Eƒ¶¼¥{ºÉððª5pµa1 )?<µЕŸ‹e}œðþ¹Ï¾€/ÍÊ_¢³œ©õÈí”6¸¦ÑeçÝòÝÕjÐnm®Ö“ڡe§mý_ÕNì®~ö,­l§˜!­÷jÐjÑ”OÙûiТÕi+ot‡ÇÕñ?zߪƫ/‰,±Þ}õ)%¶––––ÆÜšciiiiišÌj3KKKKÓ­‡7ÞÖlörù•†Å(WͲ¢B¦Ï>Å…‰¦sBwJê Ÿšû´RW6ÞöáÕ·wUâÕÉ dm•”__Î:BŸ{5l´AÚwùßE\oXLÎ<­ªÛ:è¾€3Å+n> °«þc).èÿ3ù=7öª%A]bØ? °~*@èKiÊYhR;œâR%q_ÞçL÷L+cjÆv OñÒy.)™¨b†Qù[k,øjиòŽÈÌ'×ÞŠÞœªxä˜ Ùûݽ¾ìî"GÑ}'JãlÞÆ«XhmóF_Sïsí—n}ÈJ/º¹¹¹¹ &ጛ››››kÞçÜÜÜÜ\ý ¯ï›RHQ\iX —/|5¦µ:]ZüiŸs):€z¼mÀ¶/¸ûJ´7Ãö“‹nûê»4H«“ª¬w¦~‹û+J5»àæøÒ¹÷î@V;Ûü oS¶½þãý"˜Þ»ü­m_ú!Lßð[7‚ö@„$(ö?·¥^.lï¥ó^…Àû×tôíy­h{fzß³>Pzþ¬««««Ëâ]]]]]OçáuÆÕÕÕõŒ¡á½ôŠÀ³a1á_o<Ûm8È hiQœ¹®[‡½:àb»"€"îíSp 97_ʇ/̘Öþœ«›WäÚÈ\ã¯pEÉÖ¦n®ç<î׉ø^-t1…KcZŽˆ}Š×BŸ¹WŠËXÔߨ¸Ýgj4oÂk§@©é„3êæ@jËP»ï_„·…þÒùç1ÌÜ[¥ö/À{¯q,xe_o¨`W3û-Ü„’ó÷ÑmzE äõtîŽÌ§÷zXò-ßCÕÒ‚ ݳE³ÍƯGYÏ FÌÀý%gÛëà|t[wü…mH„œÚ!s¾4'PI⻋˜fDRÅhÝúoz­‰ÍÈ’Jo6ö†·Îk§AŽ$ˆûµ¥À¼>öŠ*Æ5§ÿG›~=×|êÁß\ˆ—Æ—]{†¬0·9T\º­¯;©SrŸ{aI‚®úðö;QÑZ´S="¤¦áUÙNw•°Oªºöáù຦3àDıÏ|º]XØšºkñš{·—.Jv/º¼ÃúY›‘ƒÂyÉÒs¤›¬¯ïXt.½¬„üŸî-„+K–߇ÂíöÑ$.²šgkkåÀ-«yWRvÚ/ñìu+õ‰FivKãવµó>+[7Ò×X-ˆ€ÇKל¶ÞœEÃr«oÚÍ€,ëæÀ“;7³û=(Bâ÷¨ì»•Ä·c!Ãÿ¾ Â?J\j¹„kÉþâ, ¸ƒûÝÌEúP<öHö’J·4ðŽx_ä&Å_ÏÂÓ*ïùŽTå-ý©º*ðº}`cÿ°»us_½¡ß]8>àà<æO:0Þ±o2|mÎíá{ḭ́nÎÑäm©µÞCƒ{sÀö.´ýîäÚ~Ñš’88ñàÌå:ÇZ;$`A½=~¯àÝ;y¨Cå}âSC̪oF»³ðcÀ½º9;ÃØ±Ðsš=ªúû‰¾\ŽwÿùM#cå½öPøùA‚Z'p½U<‰µ³€#pâ=ZšÂ¬©Ä×J$êãHòZ§¶¹ Ë“ü_©Æ 6÷¹+•¤ôJüÄÊ„§@uéçS‰†×dxJ|ÍNBT÷}•?T–ô@Sx74Dô—‡I÷£x"'ÿAÐ# ‚Âó!"Xž®ˆLÈ *ëÇÝ“¡‰| ¾“§ÒDIäÀ‡iA¡ZH ’U[·A_UVh>2¸ëÒ€²¾Ý¸x¼ª°žÌÜrsÈpü캻‘zþ ;Û&^ã¿ÁÓÃýjÚía'·³­þ¿BåªÅ«Ë[þ$——?ú3ç}‚%}5äVÉêù@d±úØû¼I°®gmðß|´¡êRój‚Mføë ¯b¥Õë}¬MŽøytZãÔæx €¬žê“,†¾­&qb‡¾.ò[ýÛ Ð ¼ÿT¼ÿ)U_UVqÉ{qIÇ©½œ¼aÒH [+«çCl<^S¡"j×[´übóÚ/¯áãí]Ÿ¨O•W•í®hÍÜ=W:Fã9[©¬s‹è—Xó*ظÀgöÓ£HyõºÀkðxcš[nX_åÙðá‘*ÆÛá¢e·U=¤¬ÜúôlS«ØÜÅL /Ý4p¹i³JÏ©–³ççîa>e‡\à5x¼±ï÷9¼Ê3ò­£UŒW£ïkž®0\Z¬A+WË5 ,Ñ©å:4Å%@i±ò¯<·Òú¼ÿˆ>ouFàx^÷Ÿ9Ú ð ¼¯À+ðV'ÞÐHü¥ öæ Ȫh…=Òo|p&ļoµâ}òÌÐ×ÐyGAaÏúMºÁ^py€ÅŠ§Ê»õ€9ë^·Zñ~òôÌîsë«ß ÛÝäù-³ŒD·Aà­v¼-+ªÊ›ŒhbñE§¹AìüêgŸ™º°˜ã__!Ðè53wû¯hk“¾Àt#üûmD;ÅÜzì× hŽ™šì.xÞªÅÛº¢¨T§^a­éB­ã‰äÚÉï$gµÚ‰æ-t»?RkÑõ göàÑ"¦¡í6…Ò¥š'=g—²XAɸõ¯À[uxÕþ>>ï[ù^‹,ûqŒ«ºW,_Ϧu‡îf臟?4”>õüaºôš®ˆE]òàKs?«6¯À[uxUŽGÞìpÈ`£Íû“f71ßS·t7~ï¾AûöÖõÕãçÆwg98¿T¥xk~1ºZà}ÑnC›Š•ìÒvOZ059 êùÁô>ÐÝ€=‘ ƒ'@³]h^òƒ} ×Lˆi¾‡½7ƒìF•â¯)­ÙQ ¼/ˆ·ÉO­%“x à±Ä¹¤pX'YAÛÑEÒ†[ qþ `Å]JõCòqÉieÁwòŠ:Ï—u²åž]o%YªJ¼–ïô7ªÙéÓû#ï‹á] ¯ÏÝI½, `ÿT›7fM¿â1}Žÿéiæ~¬± á—³œÉ°ŸwÂx~¬ûìé.·¦Ï¾5ÃÄÂ|N"øÎ·;W¥Cef]©Ù9z°íA÷ÅðVg^¤Û0µÆ÷y«`Ò×0ñŠÑWàx^× ð>¬ŽOd$ð ¼/Ž÷cçw«<:ªF¼û\4Kƒ|þ·²Ððð†.çÈ9`ßIý¦T;ÉÒ…QK¶õ…àO¼±Zvl_åéø/‡*Æëþ´*WÛÏ%ýãtPÚþwx÷fxyó6Ú^Þ?òië¿ÿ˰RsUd=–J£óYÔc…<.E›P•PS@þ’fQ¹†€wÝG­ÇQƒ ùôb2éÅ$%ÊS—¢MÎÕ’Ñq\L i9*P%=zðÁaJóPÅEG'¥Q‰¢Ï[Ãú¼ú‰ö j·´õ7v÷Ø[×÷ögô'â{KKãDó—–¬ù~†è© f­P’0ÃÎfø½ào-ºjx·t¬8n2~×vdë…n6]÷óæ¾1+)_;ƒ3ïu^‘Àáz^ðãÄyC|ÊðæŽø€À~K–4ª#xò™?ªþ6xÿaµ °t-ßxŠz¾0·E–cÖVh“$N¤µ½ r¾:¢¾Ö8³¿­atv}ªoôçgK(›oíC+¾£ZéÐÃоìn¿”4ðÁa8ûѸ}AAWèâ(ðּЕ‹íßhow@!p:¹k¤²¢ª¬t7Æ£éàm<¬•},rëϵ_ÚÆ<¿A(å CV3^G;û~ïØ/^U ¨äÆ(&í“ë`àhriÝÛ<¨•ÝL€’—= ~ý¢1o*Ëð:¾ „7> êšÙ/ia#ðÖ¼ÚØè˜f+b¢ÒVOn4{XsÓíx »1¤nîÝÊ/®V"ô5É©ë“úRY°AàMŠYØ&&:N œÓª¿ñ;“­ž”á}ÿÈïàÍî¸6zÿ«Ïà-ìiDÔñ‰IÈxkT·¡•þt̲eòz0«ô0ç`|l*ñBÖÁAÙõpWö܇.²£5¾†ÐmØÖ©¢%íØS 0d |àHqÝ»DÖ’BW‹¢pÔ/_'J’€óË@Ópú=0í­ÂKÛæ ìñxkÞ§%‘¦Ú®^—%K“~Ù,<´IÏèÕNíê;®öb7³q%\|dߌ4n;ºob<Þ­6­3¼ë[U´ü:iLˆoùùm¿ú³“ÏI֦bÛsµW%ó w~´Ä]v­ÁŒÇŦu=œ%ÖNǾSâ2ÄaÏì,·Fá½¥_44IPpÇÛ#-ÎÃ3ú‘§G¼"ØÝ#…‡uB½½K€xwo|ÙS š_yFƒÞ¿ÞÆã¼ÊÄ€vA]cŠÈ.Ô M+”%òÄT•ê†äf–JS“J¡45[•’PšœT ¤'>iRœªƒÜ¾CR”W¡àåkU€w]ËŠVjâ°Q½2ÉN/‘&– NËV«Ór´• …Q£ ’äï߯¾ª,ÁvÐÇ‹Ûô³fOƒ›\èØÕqÚà$537˰ª5û€¥ùÜY“RHµ©¿}mwH1¶¶¬Ý<ËfjElŽ©ÙÜE87oc„½q§ ð>­*[?ç]«-íöqì£^ÛÍ¿OÌ_YÿNyÃ,ÝÞQóF{3úË“Fæ¼¼ÏT•-_ÅÀKTT•5“Ñnæm`¡&±v6 Ûßš@¶Ä‘}-JUcÁ §^ðóàò)"ͦ¡¶F´áƒÌ•U€÷™ª² ¾ì5ôi16cµÊº·‰¬%¯ ¿SüÐA¡jqBàý[àU®Y¶ìÍÁ˺¨U]3ºGk~]Uv±Éð=Ù<¬pwõ²ß@B­‡\ù—<«á]P”ŽüdŲÿÎ+ë4¼ç[;Ãw?¼t•~ÁvrÑòï._¶¶Ъ7ÕL= ÖAŸÉpã‚üº·¹['S=é#ë0ò;øä§Þ¿ÿj@šðÐЦö¡’VMi4cø‡ÆÛž«*{¼ª[»€¸Ú ÀOކï«Ç›Q7à›aa¡‘1jToºÂŽvåxÓæWÁPYâƒPÛÖ¡¡ZàÌìÖF&ïN´Ì…¾SÁ¿a^~‚ëd¢sŸÔÚB;jÄ?ï'÷UÕ0ûZÏ*ŸŸ÷iUÙ –Ù”Ô €™}¡‡9‰hÚX§H²‚‹8üLè éµâðù—FþÕ>pò^o¤#y¢¬Óùí˜5FŽŠRª/ÏV•åv‰ üª _?[{–Ê^Ã¥n~á>p«£û=´ßóÀ÷öíÛUy>©]Õ+`êG03Õv½ pE²*5º[óG‘ï÷Š[6Ù퀑¯´ùjë<Â;-½øQË£’C«$—”¾ß:?zù9s§òþÁ½Gv ‰çn»O½t¬U5xŸŽ6øwT/šÀ O\OôðB=s„÷BÉ©ôÞ{]MMÂ;¶ }cRÂ߯ÜÿJuÄ;£Šñ^Óÿ[ÇinÈnž?—åê~Î5¶øÖÙsñáÄžñ t½/»|þJºûù« ιeA‰ç™PýÛ¥œ» ¿¸žóÐZ5xãôã¼Ü/[³¨ï´§Ã™»gúùË…Iî§o¨Â\]£Cι>þûãý;çp{ØhšÁÿ+¼†‚·0,222<Ã@ðê~Þó’À+ðþw‰š¿téÒ… åÌ«Öi5¯Àk Ý†)5þ_AÓOàý ñê4h´€öî-h‹å†‚wNßĘšØ°Îï_ˆ×j§rh$öûýa‚ISWÞåM;v¨áiÿái÷ÅðZx=í(>î,ü~ÿ Ùÿ#Ÿ¯4 ¼Ùk~¢ ÞÃûþŽ Ç·6=`ÞñècnœË…ŒÓŽ ²J/»®©& 2 ¼ÿ¼¼¿Å«/‰Ìó˜=Øûs›K©øH®“ÙcƒçŸò_­³¾<|¥ §ý:Wà58¼`±›¾·€âz¾„H®ð ºü¿H¹úf2i¶Làx ¯b¾…åëF–s<übëåvç#ʪÊÖúü\> ‡îÎl³1õrgCmxÅ™÷™3¯óü–û&vÛ¡¼$’¤ãŸŽ,2Ëk|Œ_êäÓ^×pð¶Ü]Ñ:þ=V;ä/¸ Ö·.ÛÓÀ'I ”\+x^ÃÁÛ逾˻Vm°ëµ‰÷2'ZY/_ÙU³§÷RóW—KIéš"𠼆ƒ·¨b<Œb•®P W£ 4;óéi6/[Q«AW¢x^ÃÁ[xÞJÃ[|äðáÃ.” ¼oë¼}ëÖ­›¡jWàÝWà­,¼q „Ê(ö÷/»–÷ë‡ÿÓ¯?¿CžÏõäøk7ž¼ouàU<Ó)±½ ý# ŽJüð4ÒþŠö´wž·;ØvÓǃ­ïwOàx«ïO§{*ø*6ø+ ÈëÞ*ÛðÜ•šKãçÞ'Fò„£gaäWà­¼UÜa‹7ÓȲG;“ ¤uŠ,Çî—O¥hÝp—]S.êО³sí;=¶7ßOü É´#Z`º‘À+ðV^ýŒ9Ùò¹E}÷ËTHëþ’3Û·Dw¸¡VWøÚø‚ÍR9Þ56mP³ò—>éuLf;A® ¬ýP„¶:"ð ¼UŒWÒtqèýIJ'œÖõޤõ'Þ\ÞÒÂ[‡I­û€.Û`g£òýÚªHú÷=Âj§§¿;¥xÞ*Æ[zèç½ïŒÛ»Ó`ûâ¦S,𨀼C¿ØVŽW÷ö)2jߣÑ18VÑçÝÞJê_%¬v °ôÆÿz¯ÀûBÝýü¼ö|b=:4òê^ ø(\ÞÒÁÛ'ɨ}.[a×ógÞðÚ©@t¶À+ðV Þ*žacÍD¾;h“%Þ:‹^Yêà dÚ¢†Tq?ͱ.±)½ß)*+ÌyÒûXÝx¹æ¶$R…Ì:Uàx«ïœË­m§ÕVq€tÕ0뫆.‰´ønmæ¶áÆ¡†ÍKÓž³õðˆ%OGòˆ·6û.2‹dWà­¼ÕWàx^÷?çGsKK‹E©¯À[óðªJKKKU:Wà54¼É)Dýá^Úˆ;¿9åÆþÎ<ãŠèç*€ÓS^·ðjž¹;6j»¬ãÃßÛ!Ã84žïX?ÿ‹;gEÔ¨OŸù]d,𠼕€·‡ƒ¾YÔ#æþW¿{§7N’ðÙ¼ßüfòï-ç[ü\¿B#xÞJÀû´ªÌrÂ{Ö½ÛšÝ-X>æÊF“û! mR@¹ßjaX®Y­é?«á³YÇgÖÁ/vÖ§åv‹“ß -Û;séï ¦!÷ÌK׬'E{ÎÌöR¾Ó|;“7³oüÞã3Oëàªéº3cVå ¼ï‹ãmUQU¦ÊY2Sj´;G©},™÷dEÓ9Æ£¶š+½Ñíapí{:ø¢[úÙ¦a|~;á›hW~—~·éðò“kŒdtɇ‡rÆMÆ_’‚Oã´þiË»eߤ+þ5m;§Ÿý ¿ö7ÓÆH’4¯Àûbxµ±ÑÑ.~”^Þ8Eï‡@~­+Ü•Äsü}’þ}>&¶Ã¢”Ú‰ç Ý1À±µJÚø* RþžO$× ’$qäCÂj¥âYgNªÖê½+²˜Ò>â ŒžçëŠnƒÀû‚x+Û¿9p‰ÝIç}­æmh¾ùHËìÅñÂ%–öö6ç—­=Üi¥¯§‹9ܨ/O“„ÃøŠ>oN;Ü©›Ã±F„ÖJEµ»WÛä»N¶1¥?|fƒêõs|i¾õd¯ÀûtôUe!?u2y'¤uoq·NŽïÿz¤&F×J.Ö@'J_;ÏÈÉàÒ\õäøî)Þ îÔÍÆ¡1¡µRy¢–P¤öñLpOr==r âRhìŇ€âªWT½ò/5~Z‹‹±À½ ÷8н{Jàx+¯¾$2çä”>g>ã”(w”_œ¸“}ãOÍ7S-rÎR•GÃþg6÷Š"nèŽÝC£¸ß½±û–Žȧšœ[Qç—²7ˆ™ÐÌù!º'œ°Iàß(Pàx+oëýúæ¼íôó䵑ŸœØ2ÕÇÍ–“ëMìiL3Ëñ0§­ŠÎ pø¤€›’r¼lï ÜmAH‹Ð^î¿^'𠼕„W±ÀÒêõ>V&G⣿Úw»Ó$Ö¹ \¯kfeÝáì‘–ý6äÂ{ÇaokZ€ãïÃôÞÐÝÓîS»âKÝô)àÔ4ïœYÿH1Ú ðVÞ™W¡P´üI!/Ø2åýC?Y¸·l¢=ðy9K¡”“º«GÇ,Þs€]íh³Ž6ƒéFÐÝËnýk¼Î´¨Þu…’M¼oÕôyqÁüÍŠº÷´Ž§ÐZÙè«N9Ÿ…ca’5Ìé=-¸Ø:7IDÅhçºÓDµõåZÛ8È xÞJîóþ\Ñ2Yªþê&·¦Î8/Àwô|«¥¦Æ &®QÐtæŽérš›š›ærµýW¯4þÔO»~äÊ•ÿš_öAç8À¹qóÇ]NxÞÊÅ›¡_»*·H—¡T )19yQ‰Pš•4:‘£Ôqq*ÈOÈÍIŒ—Bb¬<-®bª§¬8-• — ¼oåâý¯¢Í{å§Jp&𠼕·hãXãÿç©÷Ž...'c^×ñþ‡Dž¿téÒÅWà­yxE·Aà­v¼«©¦Gæa‰À+ðÖ¼knê›ê>W;äA¡¾NLàx ¯þÑ÷ü+'Zœ]ùÙå µWm¥„ùø?ñõº”u=@Äy©^×ðêï°e;LüÚ©Óô#Kk/¹ À«Éœ‚ŒQ í%K§Xkqã0ßT.𠼄·õ}Ón+ýoòºw,fRj¦½#ù…äV¹ßF×ÑAàx ¯b¡µõ}lLÒ¿>|ï³[™…9Ük•~m+7êÉ Ýáˆ:&Öó>Y/𠼂WW(“}´U&“lœÜdÞ6v{ôx5ßü´ú7^’A»#‘õãe…ù¯Àkˆ}^NgÑ€¼:÷ƒS€So™¨¹!ñ%ºå½¼ްðšÀ+ðÞvW´Œ«»ù¨Æ}g“H;ž„õ·­þn+øý°pÞ1­¿ÀkHxô>=_—X¶fJQX&€|f>Üh¥Càx ïæ—K§wƒê‚$³ÒŽCàx+oØøÕOà®É°µ¯À[³ðVA^WàxÞ'OÈP¼oMÄ;qsI—pPìNxÞ€wðÓùÄ_?Šè¦¹~Wà5d¼Íw•7íf¼g7ðc›ûò5µÇo-âÄ\ûìX;“y¶7–,MµÃü5  ,*.....Ö ¼oµãmU1oƒ"nþ¤„ž›b µáu\’5$v\¬R̺xR²6~c?™ÆÖ8Þ©O2Î&ÖÖÖÖÖ6¯À[­xuY™™-Ögf”þéÇ1 òëlúF“eŠ_­ŠÚº'½{+'³õZÑmx ¯b‰­Ýýì,\pl»h×G»¯è«ÊÒZD8çFýBh·?´–¥ÝŒ3srrrr:)xÞjï6èW}÷[×Ásö Ï Ö Ðh€9Óç'q£öTŸœŠ}5²Óˆ¸äååååuE)ð ¼ÕŽ·YÅ;Æ2ù@AÃë§£ŸÖpCr‚Kí“äC—j³ÇÜÝ×€ð~çRÑZq@=>@»eäÅ€²¯/Üø×IÛI7 c¡±•'¯Àk@xÿ0¥dX«àfýÒJ;Wà­¼Wmל‡ôuO…À+ðÖ,¼¹Ç½5pê”{‰À+ðÞ ã8<^÷ÏfÓP…!DéÖFàxÿd¶Húô7€ ü¤…Z xÿ\âΜt2„œòÖ ”¯ˆÀ+""ðŠˆT^™øjD =²ßÇÛ8þ‰ˆˆ'¾ñïá½×°isOÓ†÷~oI؃OXÉïà©axE^WDDàxED^WDDàxED^WDàxED^Wäoÿ?›q"Ï>„UIEND®B`‚yard-0.9.12/docs/images/handlers-class-diagram.png0000755000004100000410000002550113206751010022003 0ustar www-datawww-data‰PNG  IHDR+ã6ÝkPLTEÿÿÿÿúú9fÚÿÿff¶ùùÿÖ‹f99d99Žÿù³ŽÖùf³ùÿùÖf9ÿ³d¶d9‹ÖÚùù9ffd9f¶d8‹f899fŽ88Ž88ff¶f9Ùÿ¶Ú‹8ÚÿÚd³ŽŽ9f9Žf8ff99ff8dŽfŽ9f99f99µÚŽŽ¶Že›9898‹ŽŽf9999ŽŽ¶ÿ¶µÿ¶ŽÚ¶9޶Ždfdfdd98df8‹µÔŠŽ‹d¶Ž9Ù¶fµÿÚ¶d8ºŽV¿¿‰¿¿£‚fŽÖ³8ey9›f¿£k8yy¶ÚŽfŽŽ8y999d³Ž8dfŽ¿‰LÙÚÙÿÚ19Ž0Od‹Ù²cfd8Ž‹8f889‹‹eµÚf¶ÿŽÚÿÿ¶ff¶fÚŽ9¶ÿÿ9ÿÿ¶ÿÿÚf¶9ŽÚÀÀÀfÿÚŽŽ99Ž99fff9Ž99ÙÚŽò¨Ðy)‘IDATx^ìÛÉjÃ0@Që“çŒC§Ï¯%Ȫ†ˆhÎÝ(ÚduxRÜT“âÏ5/’â _ VþQbE¬ˆ±"VÄ +ŠVÄÊ#SäXù=+SlÊâ+bå‘¡RbEæŠX‘ßAOH¬Ès[±RGòß¡XQÔTÕVM==ÍŠX+båt:ÕjE¬ˆ±"VXa…V.·X:²²!V'ãܲ²)VºHÍXÆKYR&+~Xaeè§Ëg›—¼æ¶,ýÄÊjî+]DF’…”C©‹ÄÊÏœAÇŒd(B"úiŒÕ/+¬ì·qnï§Î)ïÖcÅ\#íÎs»|Zv) ZóŠûÊ¡Ù_#Þ#•3¨è‰Hæ +žÛ²ÂŠX+ÏH¬ˆ±òøÄŠX‘÷™kµ"sE¬ˆ•ªbeHû·¶ÙV_·Xê§ý5ÒkYa国3ømã¸Â¸` (|ñ%ÐÁ‡*jˆ[·€a'çNhôP´=rI‘”(Ö¢eÕ~ßÌ~Ú£‘<š¬Ì]Ï|"gw9<øa×ó›÷ ”³ÃÕ}Y9?¸xäÍÉ«‰AV+b|˜‹ââêËÃß™BÛ:*ÍÁÅÓ''«¹3$gC{…¬¸÷ªX+¸U,7FÄÕd~²:ûÍÌapñ®ñ–ç–¢6n°+uÞWÄÊœBµ²hŒ•Æe#PäxpØXØ€+-+°ã •ZYQ2$|RYXæñd`˜¥ ©dÅÍ탺X+üikÉǾm ã`~5Á¼•ƒåɪ:Vä$\<žØŸÛÊáÈp ضBÜ™-6n¸ÁÊz{^+b…?mí¾ò{Ë4~òOÏâ{²V°ÿ£JVä$ø”°Â+ ±â€|”ðÿ¶ ù+ ±¢+bE¬ˆ±"Vä¯@8âà”Xi©ƒù+ù¬DJKù¬È_™x[Å»*^a±#œL/mIzn¯Nfyü5¦DJKù¬È_­bi ‹ýA]Yoˆà?ëd¬Õx_‘¿b„ ­Paºâ´÷²SÊ,À)RZ*`E9ÈÛ*Ž*,PWvXÁ²*-U°"Åi… ®“•ë™d%TZª`EþŠqV¨°@]ÙaWÈJ¨´TÁŠüØ*ëíɪUXÜQ«®ì²Ò^+nJ¨´ˆ­e(-bE¬ôVZÄŠX‘“0{ÄÊÙ[Úvëç«q²òù]+ßo¿ÁÑÇò‹÷O±r{ˆ•¿®¸Ré×u_¹#ÄÊßO¨†Ÿ¾6tÄÊÞ¡4+´Vp”[}žåÎÝÛŸ·6ô`åŸW`e”T‹Z+8Ê®¾²ÜØð~ƒµÇ~÷•ñ²"Vh­ðÈÛ(ëmã0̯>xEå#ÕWla`}ù'÷6+=¯Œ’±Â­©ÝVzìh9mì•»«¯˜špöì«ç+{²òýÖK1#eE¬0sàµìnqüòÜÒ´ƒ»«¯¸9GF‰½Ù{ÿÿ_ä0~V”ƒ> †ˆ{ ùùÑëNgúHõ•e³læOjŠõøÅJüÓÖ^­tðË‘ùµž ÷º»úŠ›udoE³"V`­Ð_™breû‹¬|¤úÊÙ»LôtU4+b%þi C¿} ²°rwõŒabo³"Vz©*qˆ•ÜðÞòtS(+TU¿ÞZ+Î7=•ÃÊðîGѬX"?{û‡wö”ù®+C½ñбM ×Ûéu²’f¾xVNVþdy:sÃ|Úxkùdå‡ÓLqÓk¼¯ˆ0à pÜø…XÖ"ã±À€)nzu¬ˆ•©Ï-+v°+Ø:÷Ëù0¥NV”ƒ8Æ÷DGOÃûÊçà¯|*¿E¬ÝïãÁþÜÙÜßZ œò9ø+í·ˆŽ;ÏAvê²NÓ ˜‚éƒû+ðUÐ?(.¹bt»á,h3„mˆ˜‘ð[JaEþ |_‰J® > Û aZã¾äg$ü–RX‘¿ÂµB‹[K®@rŒÚ ±ÃPÂo)Šù+,¾—\¹Î˜a›!¿T ¿¥Vä¯xNX|%.¹‚ú,·µÂŒ„ßR +òWÀ НÄ%WPŸ%l3´ÞzdÚ ¿¥V䯀ôŠJ® éÜh3„Ï0#Ûo+E¯3<¹~‹X+9~‹XéòWÄŠX+bE¬ˆ±"VÄŠêÅ=¸¿w„Y48êþÒžJ¬¨þ Wqè$=• XÑÚáþm‡—o­à©xá½9*Ý}å“T~hÜ’@ÂS)œù+–… [l†§âYAy~þÍÍqÙ$<±âsº9d?!oçeîñû+ön(¸Âß+öÚaÅ ˜ÏîöTÄ sz·8sïP~Õèa!‡EÈÊúòÛg“„§R#+q?¦¿›ž¾ñÙ;Û0¿¿âÝXˆq‘°âeë»=±B'•ÏŽÙ†éøë¯,§þÈ>BN'è(¡Ú’¨ÃR%+qO@²’m˜Žß_ñxBvŸƒNgÀÝ‚ÖÏ“uX”ƒà¤‚• ô,'áâ(á©(ÑI+ ôDV°2á©ÈI@NgÞÎ0Lå$Ôà s:YÉ4LÅŠœ„tæ+b%m˜Š±2@ˆ±¢þAbEýƒÊfEýƒZo…; Yl%¹úU+ª¿o…UìÅV2V¿ÄÊžjª ê¯Ð[±M?Pl%cõK¬ì©¦Ú°9ÞÊã ˆ$ÆAÎê—ü•ýÔTÔ_¡·Âû Š­d¬~‰•=ÕTÔ_·ÂŠ*,¶’³ú%e?5Õ†õWñsŠ­d¬~) PSmx'€g¬~‰•jª’•´·"'a5Õä$ÀÊjªí—•E ¬ _SMN‚XéŸóÅŠœ±2þ+P RÁdM¬ˆ±"Và7ÁXá&m,c]<}r‚ ,ɲ,üæc†`¬VÄ Œ•Ý¢–±.Þu©†%Yvʲt_Ã|LÂ,É_É÷SFÄ ×º(ºQSá2–ª-aYæ ®…qàEù+ù~Ê8sŒnÒÆ2YaI–²,Ý×0“0 d•ù+ýÔ±²B™v—±T[X–¥ûæc†p¬Vöà¤úÔ+/Z ‡ËXn 'Ðvœä„²,Ý×0“0„ duù+ýÔ1²?q‹¬ Éø^¢, ¿†ù˜„!X «) à¤æ³‚ ‘xfÕzÐ'eeH'5Ÿ•Ä3k+Ð÷ Äe„ü•!œÔ|V¢gVù+ûceP'5Ÿ•Ä3«XIÅðNêÞXI<³Š•TŒßIíÏ žh“ϬbENžhϬb%;ä$¤µÔÌ®’±2+båþþþ­ëA¿å&m[IüvŠÛƒ@«Åë,°QŠfE¬–ˆ•p“¶?ÃzδáVmÓY`£”ÏŠüÒû+ÔPøß¿ÈAŽ!\·Ã:rüÒ9 ÔPpÖ^hhµ¸ ´QÄJÚ_ñ¹Û”ßcÞÕcÙIéûóWzDÄ 5”ð¾‚#Ì¢’ Õ_•aGËicÜ™ÒÇî¯ð¾Â7i㌿Whµ¸A¬Ü×_²bNÂñËó5Z¾)}üþŠ%b… ÎLÃÀLf©{S ú+Þ?x}øó£×-aJOø+£yúÔ!ÊÊÁâ—#+×2¤ôü•\RöÊüänKNþ‹g"Léø+Yøïù+0ýSwâ1¥§ýí}×zP¾¿"VÄJE¬ÈI+bEþŠX+bE¬äù+Ü•V+b%ß_ÉuWä¯Äé{Çéú0ýYÉ÷W2Ýù+{a%mÀôg%ß_ÉwW´vÈ¢jLë@"ðXðÁΕhÎ Ì‹lÖ„ÓŸ•|%×]‘¿‚ôÍ쎴 ð™÷Xðͯ¸¿B›5mÀôg%ß_ÉwWÔ? @rgL5øÌ1„Ü̸öµV~…6kÚ€éÏJ¾¿’ï®(¡êÊNvgjÀgX›³Á+~¿B›5mÀh=hüþ ï+ÈîÉûJ(«’¾è¾B›5aÀ|6¬¨PXT-þ½‚ÏðÁΕxæE6kÚ€?+òW¸ Ùݧõð9 àš-^ñ/~Y-aÀˆ­¥ ˜X+¬«–7'߀)9 òWÄŠœ¬F'B¬ˆ`73=bEþŠé ÷¶ÌÅŠü骿B3ñá˳ ì¯ mÒÈ_éÉJÿò,Cû+÷¶rä¯|‰^AHí”N"OÅÿà²ÿ—Ú^hx §Bþ zu©Ò ­æ ¹¥üÍ'i/4~Eþ z"H'¡•BV ƒÉñ·Ü_AË»t(µ½‚˜Úo´÷ YY_~ûl’Ñ^Hû‹ª¿‚^ALía«„ïTg´*‰ù+èÔ¥vJ'‘§‚9í… bEþJ×+ˆ©i<öTÖ[+Xù<£½PQ¬ÈIÈ-|q”Ñ^¨VÄJì©,í-£½Pù¬ÈI¿"VFî$ðˆÁ§=z bE^\ÄJtQ¬È_YAZɲ»åúÑ7îØ_€ÓR1+b…ÒJÔ^9¸*òWL¥ÿ)JßVIk ÃVXؤs&ñì¾þJÀJPy嶽ܜßW°¡»f…Ù˜~awâý9¤ùüEý•VÂÊ+á^îõÖ#ÓθµÕ&Vî¯ ¦yœØ<&ñÜEý•VÂÊ+á^n|†ásY± Ý•û+d…i'–ƙċZ¢¢•µ¡»b%f…ùÉžy«pVÒKbK\ªØ_!LËíÑrô­õ ù+`Å‹¨/v…ÿhd±a=+bEþŠX+bE¬ˆ±"' Ób%b…‡ÄJ2ä¯ü…‡ÄJ*ä¯ÀePÿ DÈ_AÇ!õJ‡üsèêí䫨°†š]af瀿bGÕöòƒœ‘·™Ù9 ä¯ÔÛ?– “3ó¶pÆ¿bùªÞþA$gæmfv ù+5÷Šï+afç`!Eýƒœ‘·™Ù9ÈIPÿ TQ žƒ‚ÌŽA¬¨'LÏ+bE¬ˆ9 bEýƒR½ô舕tüwÌ!Vöb…Nü”®Ìê{ú)v_“0fK5¬ˆø)dåjÒù)ºýÚ˜„!0[ŠfEA¥{¸#+ –1˜ƒ(±pàÅBYQÄ9ËW+Ç^Siýj-˜„!0[*aE¬ÐOá}…í±¨µ`†Ðl)œ±‚p™–'ÆÊ9|Z^t &a ÙR+bIÆ‹)¯ýsÐé ¾µLš-¥²¢ÐzB¬(ÄÊøC¬ˆ…XQˆ…XQ¨×YQ¨×€XQ¯}²¢P¯±¢^ýYQ¨×€XQ¯þ¬(Ôk@¬¨×€X‘“ 'A!VbE!V…XQˆ…XQÒk`ÑÐS¼†:Y‘¿"Vé^pV|衯 bñNKP‰ÓXYo¯&U°"%ìd-Âb+dåZp :üërf§ÊAuø+q °Ø `}– røúò TÄJq½è¬Ü,¶‚8ž• #ÁzûêÙ¤Vä¯ÄýÂb+Ôg‰ï+³e-9HþJØÈ a±•Ž•s°t$øëå,ñ($VŠë5@gåF±ê³Üò”µ7D¬¨~¼X+l$VÄŠœ…XQˆ…X©-ÄŠX‘¿"V䯈•Ì¿âÅ•°G,{q+òW¼¸˜)ö â Vä¯Ä=íÝAÔ@H¬È_A“©ÀL¹Ñ+ƒX‘¿ßW¢^AÄŠü•ÀLY±W±"Jðö ZüŸ½{ÙmÛˆÂ<¨ ÞttÑE»ê¦E»+Ðu¢/0¤¬«UÉÎåõËÃŒB’IZü~D޳0$|˜¡N˜3Sø$ž_VDŸ„á#yD™€gÚç”/y~½°Â +9¥“°°"¹¼º#¨\‹°"¨¼aEóRgD0V„aEXV„V„a¥—§IÓ¤ÂʨÞ?+¬+Š +¬°2¯Î·"¬°ÂJtSü³t³jþ 1û;VÃÊSNâUþœmÓlËÊAX)Nb,®½ù¥få«a%ˆDñ¿»údź]ò¶éhXa%šZ-î+©ÊÊñ°’9ÿu»,¦ÍïKVNŠºíþÇÄÊ)ae±ªGc…ÿÄ + +¬L/¢×ɱ®ŒÇа"¬ˆ Xa…VXa…aEXyͰ’ÏÉ´¬°r†8VXaEXé5¬t¯¬°Â +ûï–¬++ë]¾_¦ÞýQ§ýSÎU;[Õ/»T°ÂÊ|›)†Ùª^_ øïÁ³ÿ|Ù¥‚VBÇúvÙüI›÷uJ)fa(¥—]*Xae—s^Õû»›ÏVæ9ß/c–ÒË.¬°r»ŒIYWÖ»h—TÖ•ƒ.¬¸_™}¼)÷+¥7Åæ±%Ó\±ò"¾­êÿïëhSñüðx— VÔmCNg— VXÙ<Ænw— VXQ·V#¬èíðzV†Ê4­¼Áß‘ÿÄߊVXa…Vâó¼.+!„•s +û§Üd›ºÃ +Û“{:³ÂJšå*-Ú奪 ”øa…•ù}< CL竺b–Ž…÷+³œI‰M)›‘XÉ}äT+ö m ™·BâÖEŽlÇb%½~N´ÂÊz÷+IÙu¹ŠÙñ°b]i€¬w«º¹ŠÍ'óŠúÊCûàÙ‡\µ{P«'7“ Y ¬œ‘+´Â +¥þÌ +—¬?³ÂJwý™Vί?³ÒC±r~ý™{Pwý™VºëϬ°Ò]f…•SëϬ°¢nË +¬°Â +¬°ÂʘkÃCuL`åx¬+ÖVXa…VXa…VXa…VXa…V@âUø”YsUö 0ÔÌbxÞ†¶i+Ã?ok*Væ±Ë”Ùç´Vv9zQ<7· Aê+“¶&ªÖ•¸*‰½) MÙŠïAÏH>Õeöâ~%„“ÖŠú +i‘Ûo>e¶yüâ{Ъ.;Tк»¹6+¬¨Û²ÂJõgVX)õç©Xaåüúó¬°Ò[ý™•Òƒ•êϬDþû–äøx¾1=X9·þ<+¬ô^fåt*)åÑY9¿þÌÊå“Gõ>óõgVN§rI,궬°ÂJ~Ya…V.^¸c…•¾Þ¥çm{+ýÖYa…VºêÏS²ÂJïõçÉYa%wPc…VXé©¦È +¬°Ò]~‹Vò42·ÅÙ›´’:rŸñ[·Â +¬°Â +¬°Â +¬°Â +¬°Â +¬ä>rVXI¯VXa…VX¼g)+¬°Â +¬°Â +¬°2|± õ.¯ßÊõõú÷²Â +¬°22åƒü¶áÏ}`…Vþgï\v†(©lø,*,Ê® uÉ·Øy8̓< ý}f&·5m*9ƒX4©T»–rœ•ÛÞT|ŒÀ>NŒ=œ_¹}<diN7(\ñ ó5Sï øÃJ0ž¤.®l‡UÙm'>ü¹+ý—+nsˆ=æW®,®¼ÞåÅݓԕ¶¯"‡ÞsojÃo0J¿ÒGq'—ͦ§&àÊ„›N)5$À¸Š9Û•²ÛuÕ±® Z«Þ¶+»Ï¸½ChÒÞš*W†u—æGWÚCÌêG‹F\¡ó¯ÐJ÷ ¢#‘W|˜’vxëÒ® Z€ÒoÛ•:³I5Vœµ÷sÞŒ1Rn0Jò`z¹G Ï~È"cO)õy˜‚©pű®œ¢E7ðæ]qüÁÞ6ãê;YãòT³3WÜèŠá«ºâAp…î@ \ña3™:WÊnX® šÝ0š?¹¸’T™…+mÏ{Ï©+XdW—]AW<(PWèÒ3î v$l«±ó‹+íÃK<ºB«oM ðŠ+\‚±ä.ö¬ÒLWÂ)“0%3ì ”¯ÑD³¦àÎ.®p}]á'š˜zêJÙóuõ¯RÅí¼ºÐå{P”]„é™aWÊŽ@Ä­FW$ÀZüfïîu†¡0 [´bagb@âÂlBÚ¦ü©×ÏùKf`°“SÁkNåk¤ÇNEޝîÛrß+XÁ V°‚¬`+—ÿ–,‡4‡£ü;V˜W˜W°‚¬`¥‹iÞþ³¬`+œƒ°‚¬`+XÁ V°‚¬`+XÁ V°‚¬`+XÁ V°‚¬`+Xáy[ž·e^a^Á V°‚¬`+XÁJŸŸOKXñMkŸ‹ƒ²ßKXñJkœ‹•ìãðÕÎ÷Û‡imÙ»Ûça^Œ2X±=¹ÓÅRj­x¥-“‹Sp »ÑHœ7ݼ¬gèÇÐi‰ë¤bÝQ²J©µâ•Ö4+]T­#(}2+IóôÛÕ0Ø_Oƒ>h‡JîÕ+wHs;Jÿ;å+žƒ¤ O¢?±¹ÙHÇ«™*ËæRgÅ+Í!·âíB§ß5EԵŭHEb?ޏrA¨©:—J+^iMs±Rš ,Û´ §L@ʙܺsǶRj­x¥5Êõ·Rš¿•rÑgCìQóîdåû/„ü?ôQûr©´â•æ[ae¶Ê}[MÇÍ¿¯WšCî%XÁ V¢“žIÀ V°‚¬O+_ìÚ» Ñ«u ÿ¿¹™âx·¼~”[aªa¥¿í#ê"ÃmÁqÓØ{>uÚ|+±+HÂf%VŠŽ•ÅÞô4Ã`xRG„8qØqæ þ‚»µ)lý¾¶¢ûûØ®·tÚ$Ò‰­¼‘:“%¯­©OŒS‘q9+)Õiñ?å|?TVLH`%]›+`¬Pò»Vh^¬€°B¾•¤°¤g%¾ö7Zª§Ó`%©ö§Î>²X+`¬D+ó;ûVâkÁ Xiº>s£—ÿ·~µ؈Mçwî@WYT,œÌJIĪåäpñYA½â–»•°ØêµocVt4+›¶ÏÄݰV6íS»åW¢·9+úÙ½¿J^yè¨VdÊâ™GûLχzVÕÜÕyÜ+nV†iâgõ=+¢0kÕäf¦…+qµM—»¢’ÌawôwPŸ96ÊJ%#M§?îYiv«¡Ûß·ú®(YhÓ¤WcÅ<ªöofJ¸D¬Ð_aÅÉ È=+l­^:<+zW•â&wx-ÆÐàA+ lš(X‘Ï/æQß23!X‰©µzAH8eEù³BÒj[èzKË#Vœ²bÓD11¯˜G‚ŠÊL`8°_k붨‚òʸش¥}n¡ûjxR½b>” ÊÍ„‡Cm[ë(×—SVúŒÐÂÀ×+Ϊ±…>. lš(Â÷AšÇÌ£àÉ=3áÀJ|í¦•…ÜtÛEIEÅ×ã•aÃQê†CG×GÙ9}jËÑÆd˜ÊŠîÀT•›Gq ‘Õ„†KË á¹-žÛ‚°–y²VÀ XAm VÀJ¿DÅ÷$\QKùý+È+ úbïìz'¢0Ó&@’Ò&*-°E„®VâT€e$®¸^$.øÔ”–Ým….?ŸóÚo{ìŽëtFµÝ˜3j43g&Ky<»ìdu’sÆÊ5“±B*Œ•¥ÉX!ö °¥ÉX 0ÜcEÁðX¡¶A HuWO"\fv„c¥çªXñt×ÿ3+ÆJÏU³‚ ÞÈwª»^NƒlÔÕdÅXar¬pzø„R "žpl£’ceõR+s _y‘Ó]‹bX€Ú+%éV°2x¥-*znÜ_Õ†øò`Pw²l½2wR(è®*œÙ¨6¯4Å ÓͳrRÅ ò¡â’îªSG ê³b¬ n§Ÿf÷%ƒSçÆimo´5NMÑósÓ6„>cwÿXá_ÜÛéo:)‹·¾tn"‘I2ÜþI¶—hgmãp³Y¹<þ V`£¾KÑžbiQ8 ´Q}VŒ•­I2ÛO³Í½ÑðdÂH6wÐ$#©MÙÆZúV¸…ÁéX˜è£HVî ¸âp±;ÝÜékç\#pVœ$èÊ=Hʪ»…Ó0ÕgÅXðËŸì#  –µ N¿FDjø°5)ñ†—¢žK°9ù 8\ŒQÔι6F8H+ÿzÆÊÂ99?àd“²²…³j‰Ô¿y8UVØÆZ+ÜBœJÉgEþŠsmŒ¬+ÆÊöyV0è/6{0I”¶yó ·@öp")cEíœkcdX±õŠ.?xt8Ð.¥+lc­°^áJY9+‹}ĵs®‘ÛÌŠ±’®÷³KžÙ÷òãÍ®nÜø6ȳ5™TXcg=K•ƒ~dvεé׳1¾ÛY1'Á;¦“›I@""ù¬Ø{ÉêHa¬`–àªTÓ X±yÅœcÅX1VŒ•æ’±b¬+ÆŠ±2?|ö÷¯³Âq›fÅ»ñUƒ Ð]V”§ëOg…ã®+ÆJʯ„çÛ®ßMµÞ7_ƒzéà^J&VŽœfá£Õ0n$+0EQLQk$óOhªø’I%³°3·ÞV„ñ©Ž‰³µ£ì1¦½ùqïèlíÙ_‡È¤òûsôÖ,|´Æd¥¨¢Ð:¡BSÅ—L"evf`eY9rHðªÊªË!Î ¾ô$âéËi±‡ÈX‹!³®qãÏAê”K&‘2 ;#Эs(˜|€Í«kè¶H%p>ÒœYðh5ŽÏ ž,¤@SÅ—L"evf`õY< Ko]~âÄÀ,x´úÆg…N ýš*žd+³°3¸’ÃXþ [‚’[7H5«HY+5ŽÏ ’Œ|hªø’I¤ÌÂΨt.1±"x³|ÊÊ¥ëÄÅüEŒYðh5ŒËŠ˜"„ uJô\ASÅ“Lbevf 3÷m1ù7î¯p\»oÛ-VŒcÅœcÅX1VŒc¥æd¾­Í+ñGÜIIYip\c% +±NãžsàGø?äÂ}“­qŒÃÐ}VŒvžíN;ËJ É5>b¤¿’VËü”„AÈ)Œ†Â  SìÃ[ÚaÅX‰ôWÐTê§09…‘ü¼rÁJZÜŒ|xK5+u™¨ÆJ¤¿r¥Ÿ¢Ad…õŠðtÁ HÇ>¼¥š•VMTcÅ÷W®ôS AFP” ADZbÞRÍJ»&ª±âû+Wù)¹ #„!™ÁdÒy-±o©d¥]ÕXñý•*?…ÁâzEàÈ,]0³•º1o `¥q¶‰TŠk+]Ï_AS¿ÌOI4ÈaH•m´þ²ë l-öá-(.c¥¶þäJKí$פ“0x\›“ÐŽ[W2Vf{£XiÌD5V:é$Ä›¨æ$TïKXiÇj IÆŠ±‚UñsÌKù× Ið8üÕVq¬Ìó¿ª{âG‚w£û¬hª›•¬ÎÀ ©VøÊ5Ÿ?Ý?Ò&+ÆÊÇr›fýîùõ7.ÖÏþ==À]ž,ÿ´å¬1ޤÛÄd“îÉZ~0î[ÀnÜ,+ÆÊ§¸góÕÅ{Bpìòg|MäkЖ³¢óGÒmöæÙ JŠƒ!´aå?öÎ.a‚§ðÁè%<е¦Uÿ¨ç·“¬l—¼dIãKÙ—˜a[!ð½o«]ñ®ª; ec¦("<ò´ì®8 T”Dð,)Ķ‘zù£])xS ]À"o»‚Àx ½WDItÌFšaÄ0!l7'&Ò•ºsX ’[ºWÞÁ ‘ß+v¯„I\ V “LéÊ¿+×Å PŒ™b[CX4ý´­T)&î_¯+† aã»RæhWØ”`Ì€A[ÇðÌaИ® ,AT”Æï œl¬¼eÛx²w?½N2QljÜĸ¹ãÂ…1ÆD¾ ׺Ñwàp¹PÛbÿ<¾}çÐÐ&$¨3µ~OªS áÃg¦påV"ÆüZ"Z¹ýŸÛÞ¾¬`+XÁ V°‚¬Üþ< õ`…q…q+XÁ V°‚¬`+XÁ V°‚¬`+X¬`EÁ¸‚¬`+XÁ V°‚¬`+XÁ V°‚¬p¿-VWW°‚¬`+XÁ V°ð)hî"y±4"=Í]$/V‚F¤§ ¹‹åÅJ°ˆô4w±¼X ±ž‚v±¼X ‘Ÿ‚6?/V‚Eì§ ÍÏ‹•Pó)hóób%dÄ~ Úü¼X ±žl ï``+Xឬ`+XÁ ÷Ûr¿-V">­(òÓ{°‚¬¬`%Vð¯Ä V°‚¬`+XÁ V°Â< nÀŠ»¦ÀÊÕä´rƒ£V°‚¬`…{âß§€¬`eµ;Ü2_t™Vä.Ë]¥w‡W²}¡•Û½_Sý>Wñ¸°-ÇY)œóy-Ã@tµ¥I}޾ÈQµaerÞÒep²¢#a–Ö¶" ujð†¬ Õ¦ˆb+b¢ãU¶½ÑBîúfš•ùycZÁŠE¾Nʪ™Ñ<·IÖ²$)ª$¯ÓÕ.³Æ/”k“Õ7Ó¬ÌÏÅ Vrç43›A)2o%³o…í“Ebù´y›Øb–F‹y#Xá;È™±?ÆæYj:6Í4Ú¦\Í$+ó󯵂S¡=Ø¿mA‘שšiVæçk…ë ßýË&›4äè¼Á/üKÍ4+óóF·‚búýÎFùÆÊñõˆþN gŸ©™fe~ÞxV°¢¸øÙ£¬„ΫÀ V°Â= XÁ V°‚î·å~[¬ Æq&oÜÀ V°‚¬\yX!°B`…ÀÊ-+V¬X!°‚+V¬X!°B`åW»vNA ­Àÿ*æ [náþùN´‚Vøõù°»èÑѦÖkIEND®B`‚yard-0.9.12/docs/Handlers.md0000755000004100000410000001521013206751010015601 0ustar www-datawww-data# @title Handlers Architecture # Handlers Architecture Handlers allow the processing of parsed source code. Handling is done after parsing to abstract away the implementation details of lexical and semantic analysis on source and to only deal with the logic regarding recognizing source statements as {file:docs/CodeObjects.md code objects}. ![Handlers Architecture Class Diagram](images/handlers-class-diagram.png) ## The Pipeline After the {file:docs/Parser.md parser component} finishes analyzing the source, it is handed off for post-processing to the {YARD::Handlers::Processor} class, which is responsible for traversing the set of statements given by the parser and delegating them to matching handlers. Handlers match when the {YARD::Handlers::Base.handles?} method returns true for a given statement. The handler can then perform any action after being invoked by the `process` method. ## The Processor Class The main purpose of the processor, as mentioned above, is to traverse through the list of statements given to it by the parser. The processor also keeps state about what is being processed. For instance, the processor is what keeps track of the current namespace (the module or class an object is being defined in), scope (class or instance), file and owner. The owner refers to the object that is most directly responsible for the source statement being processed. This is most often the same as the namespace, except when parsing the body of a method, where the namespace would be the class/module the method is defined in and the owner would be the method object itself. ## Implementing a Handler This section covers the basics of implementing a *new-style* Ruby handler. For details on implementing a legacy handler, see the "API Differences" section below. a Ruby handler can be implemented simply by subclassing the {YARD::Handlers::Ruby::Base} class and declaring what node types or source to process with the {YARD::Handlers::Base.handles handles} class method. A very simple handler that handles a module definition would be: class MyModuleHandler < YARD::Handlers::Ruby::Base handles :module def process puts "Handling a module named #{statement[0].source}" end end For details on what nodes are, and what node types are, see the {file:docs/Parser.md parser architecture document}. In this case the node type being handled is the `:module` type. More than one node type or `handles` declarations may describe a single handler, for instance, a handler that handles class definitions should handle the `:class` and `:sclass` node types respectively (the latter refers to classes defined as `class << Something`). The {YARD::Handlers::Base#statement statement} attribute refers to the current node (or statement) that is being handled by the handler. ### Handling a Method Call In some cases, a developer might need to handle a method call. The parser can express a method call in many AST forms, so to simplify this process, a method call can be handled by declaring the following in a `handles` statement: class MyHandler < YARD::Handlers::Ruby::Base handles method_call(:describe) def process # Process the method call end end In this case we handle any of the method calls to method name `describe` with the following syntaxes: describe(something) describe arg1, arg2, arg3 describe(something) { perform_a_block } describe "Something" do a_block end ### Creating a new Code Object Usually (but not always) handling is performed to create new code objects to add to the registry (for information about code objects, see {file:docs/CodeObjects.md this document}). Code objects should simply be created and added to the existing `namespace`. This will be enough to add them to the registry. There is also a convenience {YARD::Handlers::Base#register register} method which quickly sets standard attributed on the newly created object, such as the file, line, source and docstring of the object. This method will be seen in the next example. ### Handling an Inner Block By default, the parser gives the processor class a list of all the top level statements and the processor parses only those top level statements. If an inner block of a module, class, method declaration or even a block passed to a method call needs to be handled, the {YARD::Handlers::Base#parse_block parse_block} method must be called on the list of statements to parse. This will send the list to the processor to continue processing on that statement list. The source tree can be selectively parsed in this manner by parsing only the inner blocks that are relevant to documentation. For example, the module handler parses the inner body of a module by performing the following commands: class YARD::Handlers::Ruby::ModuleHandler < YARD::Handlers::Ruby::Base handles :module def process modname = statement[0].source mod = register ModuleObject.new(namespace, modname) parse_block(statement[1], :namespace => 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.9.12/docs/GettingStarted.md0000755000004100000410000006200413206751010016774 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 Attributes To document a Ruby attribute, add documentation text above the attribute definition. # Controls the amplitude of the waveform. # @return [Numeric] the amplitude of the waveform attr_accessor :amplitude As a short-hand syntax for declaring reader and writer attribute pairs, YARD will automatically wire up the correct method types and information by simply defining documentation in the `@return` tag. For example, the following declaration will show the correct information for the `waveform` attribute, both for the getter's return type and the setter's value parameter type: # @return [Numeric] the amplitude of the waveform attr_accessor :amplitude In this case, the most important details for the attribute are the object type declaration and its descriptive text. ### Documentation for a Separate Attribute Writer Usually an attribute will get and set a value using the same syntax, so there is no reason to have separate documentation for an attribute writer. In the above `amplitude` case, the `Numeric` type is both used for the getter and setter types. Sometimes, however, you might want to have separate documentation for the getter and setter. In this case, you would still add the documentation text to the getter declaration (or `attr_accessor`) and use `@overload` tags to declare the separate docstrings. For example: # @overload amplitude # Gets the current waveform amplitude. # @return [Numeric] the amplitude of the waveform # @overload amplitude=(value) # Sets the new amplitude. # @param value [Numeric] the new amplitude value # @note The new amplitude will only take effect if {#restart} # is called on the stream. Note that by default, YARD exposes the reader portion of the attribute in HTML output. If you have separate `attr_reader` and `attr_writer` declarations, make sure to put your documentation (for both reader and writer methods) on the reader declaration using `@overload` tags as described above. For example: # @overload ...documentation here... attr_reader :amplitude # This documentation will be ignored by YARD. attr_writer :amplitude ## Documenting Custom 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. You can wrap the meta data section in an HTML comment to prevent it from being displayed in rendered markdown on GitHub: This is the best library you will ever meet. Lipsum ... ## 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 YARD will allow any RubyGem installed on your system (or in your Gemfile) to be loaded as a plugin provided it has a name with the prefix of `yard-` or `yard_`. In order to load a plugin, use the `--plugin` switch with the short-name (name minus the `yard-` prefix) or full-name of the gem: $ gem install yard-custom-plugin ... $ yard doc --plugin custom-plugin or $ yard doc --plugin yard-custom-plugin Note: you can also put this switch in your `.yardopts` file. See the `.yardopts` section above for more information. You can use this functionality 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 You can then load the plugin with: $ yard doc --plugin rspec 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. You may find some useful YARD plugins on [RubyGems][RubyGemsQuery] or with a [Google advanced query][GoogleAdvancedQuery]. [graphviz]:http://www.graphviz.org [yard-rspec]:http://github.com/lsegal/yard-spec-plugin [rspec]:http://rspec.info [GoogleAdvancedQuery]:https://www.google.com/search?q=site%3Arubygems.org+intitle%3A%22yard-%22+OR+intitle%3A%22yard_%22 [RubyGemsQuery]:https://rubygems.org/search?utf8=%E2%9C%93&query=name%3A+yard yard-0.9.12/docs/TagsArch.md0000755000004100000410000001114413206751010015537 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.9.12/docs/templates/0000755000004100000410000000000013206751010015513 5ustar www-datawww-datayard-0.9.12/docs/templates/default/0000755000004100000410000000000013206751010017137 5ustar www-datawww-datayard-0.9.12/docs/templates/default/yard_tags/0000755000004100000410000000000013206751010021114 5ustar www-datawww-datayard-0.9.12/docs/templates/default/yard_tags/html/0000755000004100000410000000000013206751010022060 5ustar www-datawww-datayard-0.9.12/docs/templates/default/yard_tags/html/setup.rb0000755000004100000410000000141713206751010023553 0ustar www-datawww-data# frozen_string_literal: true def init sections :list, [T('docstring')] end def tag_signature(tag) types = tag.types || [] signature = "#{tag_link_name(tag)} " sig_tag = tag.object.tag('yard.signature') extra = sig_tag.text if sig_tag 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 signature + h(extra).gsub(/\n/, "
               ") end yard-0.9.12/docs/templates/default/yard_tags/html/list.erb0000755000004100000410000000100413206751010023523 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.9.12/docs/templates/default/layout/0000755000004100000410000000000013206751010020454 5ustar www-datawww-datayard-0.9.12/docs/templates/default/layout/html/0000755000004100000410000000000013206751010021420 5ustar www-datawww-datayard-0.9.12/docs/templates/default/layout/html/setup.rb0000755000004100000410000000030113206751010023102 0ustar www-datawww-data# frozen_string_literal: true def 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.9.12/docs/templates/default/layout/html/tag_list.erb0000755000004100000410000000060713206751010023726 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.9.12/docs/templates/default/fulldoc/0000755000004100000410000000000013206751010020567 5ustar www-datawww-datayard-0.9.12/docs/templates/default/fulldoc/html/0000755000004100000410000000000013206751010021533 5ustar www-datawww-datayard-0.9.12/docs/templates/default/fulldoc/html/full_list_tag.erb0000755000004100000410000000047413206751010025065 0ustar www-datawww-data<% even_odd = 'odd' %> <% collect_tags.each do |tag| %>
          • <%= tag_link(tag) %>
          • <% even_odd = (even_odd == 'even' ? 'odd' : 'even') %> <% end %>yard-0.9.12/docs/templates/default/fulldoc/html/setup.rb0000755000004100000410000000022213206751010023217 0ustar www-datawww-data# frozen_string_literal: true def generate_tag_list @list_title = "Tag List" @list_type = "tag" asset('tag_list.html', erb(:full_list)) end yard-0.9.12/docs/templates/plugin.rb0000755000004100000410000000334413206751010017345 0ustar www-datawww-data# frozen_string_literal: true include 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(&: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 = object self.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 = $1 suffix = "tag" if tag_name =~ /^!/ tag_name = tag_name[1..-1] suffix = "directive" end obj = Registry.at("YARD::Tags::Library##{tag_name}_#{suffix}") return tag_link(obj.tag("yard.#{suffix}")) if obj 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.9.12/docs/Tags.md0000755000004100000410000003232313206751010014743 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, placed either before or after the types list. 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 io [#read] 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 user [String] the username for the operation # @param host [String] 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.9.12/docs/Overview.md0000755000004100000410000000502513206751010015652 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.9.12/docs/Parser.md0000755000004100000410000002125113206751010015277 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.9.12/docs/WhatsNew.md0000755000004100000410000015144713206751010015616 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) 21. **Added `stats_options` for the rake task** (0.8.7.6) ## 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.9.12/.yardopts0000755000004100000410000000105013206751010014432 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 - CHANGELOG.md 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.9.12/LICENSE0000755000004100000410000000204413206751010013575 0ustar www-datawww-dataCopyright (c) 2007-2016 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.9.12/benchmarks/0000755000004100000410000000000013206751010014702 5ustar www-datawww-datayard-0.9.12/benchmarks/splat_vs_flatten.rb0000755000004100000410000000060713206751010020605 0ustar www-datawww-data# frozen_string_literal: true require "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) } } end yard-0.9.12/benchmarks/generation.rb0000755000004100000410000000221713206751010017367 0ustar www-datawww-data# frozen_string_literal: true require "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) =end yard-0.9.12/benchmarks/builtins_vs_eval.rb0000755000004100000410000000173013206751010020603 0ustar www-datawww-data# frozen_string_literal: true require '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.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) } } } end yard-0.9.12/benchmarks/template_erb.rb0000755000004100000410000000126013206751010017674 0ustar www-datawww-data# frozen_string_literal: true 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") 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) } } end yard-0.9.12/benchmarks/yri_cache.rb0000755000004100000410000000066213206751010017164 0ustar www-datawww-data# frozen_string_literal: true require 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) } } end yard-0.9.12/benchmarks/marshal_vs_dbm.rb0000755000004100000410000000355713206751010020225 0ustar www-datawww-data# frozen_string_literal: true require 'benchmark' require 'dbm' MARSHAL_FILE = "marshal_test.db" DBM_FILE = "dbm_test" WRITE_TIMES = 1 READ_TIMES = 100 NUM_INDICES = 10_000 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.9.12/benchmarks/pathname_vs_string.rb0000755000004100000410000000357513206751010021137 0ustar www-datawww-data# frozen_string_literal: true require '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.9.12/benchmarks/template_format.rb0000755000004100000410000000046013206751010020415 0ustar www-datawww-data# frozen_string_literal: true 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") log.puts Benchmark.measure { obj.format(:format => :html) } yard-0.9.12/benchmarks/erb_vs_erubis.rb0000755000004100000410000000221713206751010020065 0ustar www-datawww-data# frozen_string_literal: true require '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 end yard-0.9.12/benchmarks/concat_vs_join.rb0000755000004100000410000000056013206751010020231 0ustar www-datawww-data# frozen_string_literal: true require "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.9.12/benchmarks/ri_vs_yri.rb0000755000004100000410000000111213206751010017232 0ustar www-datawww-data# frozen_string_literal: true require "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.9.12/benchmarks/registry_store_types.rb0000755000004100000410000000301413206751010021540 0ustar www-datawww-data# frozen_string_literal: true require '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.9.12/benchmarks/ripper_parser.rb0000755000004100000410000000104613206751010020110 0ustar www-datawww-data# encoding: utf-8 # frozen_string_literal: true 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) } } } end yard-0.9.12/benchmarks/rdoc_vs_yardoc.rb0000755000004100000410000000120013206751010020223 0ustar www-datawww-data# frozen_string_literal: true require "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` } end yard-0.9.12/benchmarks/template_profile.rb0000755000004100000410000000077113206751010020572 0ustar www-datawww-data# frozen_string_literal: true require '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.9.12/benchmarks/parsing.rb0000755000004100000410000000304613206751010016700 0ustar www-datawww-data# frozen_string_literal: true require "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.9.12/benchmarks/format_args.rb0000755000004100000410000000237713206751010017547 0ustar www-datawww-data# frozen_string_literal: true require "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.9.12/CHANGELOG.md0000755000004100000410000006722313206751010014413 0ustar www-datawww-data# [0.9.12] - November 26th, 2017 [0.9.12]: https://github.com/lsegal/yard/compare/v0.9.11...v0.9.12 - Be more explicit about lack of support for absolute paths in extra files specified by `yard doc` command. # [0.9.11] - November 23rd, 2017 [0.9.11]: https://github.com/lsegal/yard/compare/v0.9.10...v0.9.11 - Fixed security issue in `--readme` that allowed for arbitrary file reads on disk. Credit to ztz for discovering this issue. - Improved styling for inline code blocks (#1142). # [0.9.10] - November 18th, 2017 [0.9.10]: https://github.com/lsegal/yard/compare/v0.9.9...v0.9.10 - Added `--fail-on-warning` option for `yard doc` which exits with a non-zero code if there are any warnings (#1093). - Added support for parsing inside `Struct.new` blocks (#1099). - Added support new ripper AST tokens (#1104, #1124). - Fixed an issue where `@see (obj)` reference tags would fail (#1111) - Fix sorting in `yard stats` (#1123). # [0.9.9] - April 23rd, 2017 [0.9.9]: https://github.com/lsegal/yard/compare/v0.9.8...v0.9.9 - Added `gem uninstall` hooks to remove YARD documentation files. (#1083) - Added support for C++ namespaces. (#809) - Fixed issue where loading a .html page via an anchor would not scroll to the anchor section. (#1082) - Hide some Ruby warnings. - Improve progress indicator icons in terminal. # [0.9.8] - January 13th, 2017 [0.9.8]: https://github.com/lsegal/yard/compare/v0.9.7...v0.9.8 - Fixed installed gems not being correctly found in `yard server` and by plugins. - Fixed tokenization of `%w(...)` array syntax. # [0.9.7] - January 9th, 2017 [0.9.7]: https://github.com/lsegal/yard/compare/v0.9.6...v0.9.7 - Fixed resolution of absolute object paths with ambiguous names. (#1029) # [0.9.6] - January 7th, 2017 [0.9.6]: https://github.com/lsegal/yard/compare/v0.9.5...v0.9.6 - Removed official support for Ruby 1.x (1.8/1.9). YARD can still be installed in these versions, but support is not guaranteed. Simple bug fixes may still be considered via pull request only. Issues without code will be automatically closed. - Added {YARD::Tags::Tag#explain_types} returning a plain English summary of the type specification of a given tag. Also adds {YARD::Tags::TypesExplainer} as an implementation class for the method. - Added support for automatic linking of constants and method calls of Ruby syntax highlighted source code in generated HTML. Also adds the {YARD::Parser::Ruby::TokenResolver} implementation class to iterate over tokenized code with extra resolved object information. - Added support for compound constant assignments (`A::B::C = true`). - Added `LibraryVersion#yardoc_file_for_SOURCE` callback method for sources with a pre-determined yardoc file location. Implement this method instead of manually setting `library.yardoc_file = ...` in your load method (you can still assign the attribute manually). - Use RubyGems 2.x+ API to query gems when available instead of using backport. - Various bug fixes # [0.9.5] - July 22nd, 2016 [0.9.5]: https://github.com/lsegal/yard/compare/v0.9.4...v0.9.5 - `yard doc` will now generate `.yardoc/processing` and `.yardoc/complete` files to allow other tools to properly detect when YARD is in the middle of parsing source files, and when it has completed writing the database. - Added support for on-demand generation of LibraryVersion objects using the `:disk` source type. LibraryVersion objects pointing to a .yardoc database directory will now auto-generate if there is a `source_path` attached. - Added warning for macros attached to non-method objects. - Fixed a few more parsing errors. # [0.9.4] - July 21st, 2016 [0.9.4]: https://github.com/lsegal/yard/compare/v0.9.3...v0.9.4 - Minor Ruby file parsing and CSS bug fixes. # [0.9.3] - July 20th, 2016 [0.9.3]: https://github.com/lsegal/yard/compare/v0.9.2...v0.9.3 - Added support for {YARD::Server::RackAdapter} to be mounted under prefix URIs. - Fixed regression in `yard server -g` that caused static file assets on index page to return 404 errors. - Fixed regression in `yard server -g` index page that disabled scrolling and caused other HTML rendering glitches. # [0.9.2] - July 19th, 2016 [0.9.2]: https://github.com/lsegal/yard/compare/v0.9.1...v0.9.2 - Added `yard config --gem-install-[yri|yard]` commands which auto-configure your `~/.gemrc` file to run yri/yard instead of ri/rdoc on a `gem install`. - Added support for gemspec metadata key `"yard.run"`, which can be either `"yard"` or `"yri"` to run the respective commands on a `gem install`. - Added `yard doc --no-progress` to hide the progress bar. - Fix resolution error for compound proxy namespaces. - YRI will now search across all gem versions (latest first) for the .yardoc database. # [0.9.1] - July 18th, 2016 [0.9.1]: https://github.com/lsegal/yard/compare/v0.9.0...v0.9.1 - Added "Attributes" section to `yard stats`. - Added support for RubyGems 2.x `--document=yri,yard` flags. You can now run YARD documentation generation against installed gems by running: `gem install mygem --document=yard,yri`. - Added `/static/*` routing for library-specific routing. This enables static template files to be served on a per-library basis instead of globally shared across the `yard server`. - Added support for inlining of `{include:*}` syntax. Using this syntax in the middle of a docstring paragraph will no longer create a separate paragraph for the included text. - Added support for resolving `{}` syntax in text templates, specifically for use in `{include:*}` syntax. - Improved object resolution logic in `{Foo::Bar}` syntax and {YARD::Registry.resolve}. New resolution logic should now more accurately support resolving compound paths across namespaces and through the inheritance tree (as Ruby does). - The `frozen_string_literal: true` comment line in Ruby source files will now be excluded from docstrings. - Added a workaround for https://bugs.ruby-lang.org/issues/11485 - Fixed an issue where type using a docstring reference on an `@!attribute` macro would be incorrectly parsed as a type specifier. This change updates the tag parser to disallow newlines between the tag name and opening bracket of the type specification. - Fixed an issue where `--embed-mixins` would improperly embed methods from inherited classes instead of modules. - Fixed various parsing errors and YARD exceptions. - Added a warning for modules or classes being redefined as constants. - Reverted stripping of HTML in {YARD::Docstring#summary}. - Added optimization to remove initial docstring parse on newly created code objects. - {YARD::CodeObjects::Base#format} now passes the :type parameter to templates. - Hide methods with filtered namespaces in Method Listing. # [0.9.0] - July 4th, 2016 [0.9.0]: https://github.com/lsegal/yard/compare/v0.8.7.6...v0.9.0 Special thanks to Alex Dowad, MSP-Greg, and Alex McLain for their extended contributions to this version. - (Breaking Change): Replaced default template with an updated "frameless" version. This change may affect backward compatibility if custom templates made modifications to `default/fulldoc/html`, specifically the index or navigation lists. - Added support for Ruby 2.1+ decorator style method declaration syntax. YARD now supports: private def foo(x, y) end - Metadata headers in extra files can now be escaped from rendering by enclosing them in HTML comment blocks (``). Ensure that the opening comment tag is alone on the first line of the file to use this functionality. - Improved parsing of various CRuby coding styles. - Fixed issue with binary image assets when using `yard server`. - Fixed deprecation warnings from Rake 10.x. - Tests updated for RSpec 3. # [0.8.7.6] - October 26, 2014 [0.8.7.6]: https://github.com/lsegal/yard/compare/v0.8.7.5...v0.8.7.6 - Support using `@option` tag on keyword arg splat parameter. (#729) - Add `.stats_options` for `YardocTask`. (#800, #801) # [0.8.7.5] - October 26, 2014 [0.8.7.5]: https://github.com/lsegal/yard/compare/v0.8.7.4...v0.8.7.5 - Fix linking of methods in top level namespace in method listing. (#776) - Support using C macros in function declarations. (#810) - YARD will no longer group comment blocks starting on the same column if they are preceded by code. (#798) - Handle anonymous lambda calls in toplevel scope. (#774) - Support I18n in `@overload` tags. (#794) - Support `yard stats` for objects with no file property. (#792) - Support for named arguments in Ruby >= 2.1. (#785) - Exclude README backup files from YARD generation. (#790) - Turned on the lax spacing option in Redcarpet to comply with the Markdown standard. - Escape HTML in YARD server search placeholder template. - Fix issue with `private_class_method` support. (#760, #767) - Enable tables support by default in Redcarpet Markdown provider. (#765) # 0.8.7.4 - March 22, 2014 [0.8.7.4]: https://github.com/lsegal/yard/compare/v0.8.7.3...v0.8.7.4 - Mark C methods as explicit but also remove explicit check in stats. (#727) - Report unresolved parent namespaces as undocumentable errors instead. (#753) - No longer ignore overridden methods from documentation check in stats (#719) - Fix JRuby throwing exception when remove_method called on non-existent method. (#732) - Add basic support for `private_class_method` (#747) - Ensure namespace is always set when parent module is not found. (#753) - Set overflow as auto on table of contents. - Report 100% documented if nothing is undocumented. (#754) - Added support for RubyGems 2.0.0+. (#742) - Allow users to enter their own YARD RakeTask name. (#705) - Fixed a typo that was causing Windows detection to always fail. (#715) - Add debug information when loading a plugin fails. (#711) # [0.8.7.3] - November 1, 2013 [0.8.7.3]: https://github.com/lsegal/yard/compare/v0.8.7.2...v0.8.7.3 - 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). # [0.8.7.2] - September 18, 2013 [0.8.7.2]: https://github.com/lsegal/yard/compare/v0.8.7.1...v0.8.7.2 - Disallow absolute URLs when using frame anchor support. - Support casted functions in CRuby method declarations (#697) # [0.8.7.1] - September 11, 2013 [0.8.7.1]: https://github.com/lsegal/yard/compare/v0.8.7...v0.8.7.1 - Fix potential XSS issue with frame anchor support. - Add support for gettext 3.x gem. # [0.8.7] - July 26, 2013 [0.8.7]: https://github.com/lsegal/yard/compare/v0.8.6.2...v0.8.7 - 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) # [0.8.6.2] - June 27, 2013 [0.8.6.2]: https://github.com/lsegal/yard/compare/v0.8.6.1...v0.8.6.2 - Fixed issue where `yard graph` was not displaying methods # [0.8.6.1] - April 14, 2013 [0.8.6.1]: https://github.com/lsegal/yard/compare/v0.8.6...v0.8.6.1 - 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. # [0.8.6] - April 13, 2013 [0.8.6]: https://github.com/lsegal/yard/compare/v0.8.5.2...v0.8.6 - 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. # [0.8.5.2] - February 26, 2013 [0.8.5.2]: https://github.com/lsegal/yard/compare/v0.8.5.1...v0.8.5.2 - Support new keyword argument syntax in method signatures (Ruby 2.x) # [0.8.5.1] - February 25, 2013 [0.8.5.1]: https://github.com/lsegal/yard/compare/v0.8.5...v0.8.5.1 - Fix `yard diff` of gem files with RubyGems 2.x # [0.8.5] - February 24, 2013 [0.8.5]: https://github.com/lsegal/yard/compare/v0.8.4.1...v0.8.5 - 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 # [0.8.4.1] - February 5, 2013 [0.8.4.1]: https://github.com/lsegal/yard/compare/v0.8.4...v0.8.4.1 - Fix regression that broke loading of existing yardoc dbs (#648) # [0.8.4] - February 4, 2013 [0.8.4]: https://github.com/lsegal/yard/compare/v0.8.3...v0.8.4 - 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) # [0.8.3] - October 14, 2012 [0.8.3]: https://github.com/lsegal/yard/compare/v0.8.2.1...v0.8.3 - 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) # [0.8.2.1] - June 9, 2012 [0.8.2.1]: https://github.com/lsegal/yard/compare/v0.8.2...v0.8.2.1 - Fix a set of regressions in yard server search and dynamic generation # [0.8.2] - June 7, 2012 [0.8.2]: https://github.com/lsegal/yard/compare/v0.8.1...v0.8.2 - 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) # [0.8.1] - May 2, 2012 [0.8.1]: https://github.com/lsegal/yard/compare/v0.8.0...v0.8.1 - 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) # [0.8.0] - April 30, 2012 [0.8.0]: https://github.com/lsegal/yard/compare/v0.7.5...v0.8.0 - 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)
            
            # [0.7.5] - January 31, 2012
            
            [0.7.5]: https://github.com/lsegal/yard/compare/v0.7.4...v0.7.5
            
            - Various minor bug fixes
            
            # [0.7.4] - December 2, 2011
            
            [0.7.4]: https://github.com/lsegal/yard/compare/v0.7.3...v0.7.4
            
            - 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
            
            # [0.7.3] - October 15, 2011
            
            [0.7.3]: https://github.com/lsegal/yard/compare/v0.7.2...v0.7.3
            
            - 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)
            
            # [0.7.2] - June 14, 2011
            
            [0.7.2]: https://github.com/lsegal/yard/compare/v0.7.1...v0.7.2
            
            - 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)
            
            # [0.7.1] - May 18, 2011
            
            [0.7.1]: https://github.com/lsegal/yard/compare/v0.7.0...v0.7.1
            
            - Fixes a bug in `yard server` not displaying class list properly.
            
            # [0.7.0] - May 17, 2011
            
            [0.7.0]: https://github.com/lsegal/yard/compare/v0.6.8...v0.7.0
            
            - 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...
            
            # [0.6.8] - April 14, 2011
            
            [0.6.8]: https://github.com/lsegal/yard/compare/v0.6.7...v0.6.8
            
            - Fix regression in RDoc 1.x markup loading
            - Fix regression in loading of markup libraries for `yard server`
            
            # [0.6.7] - April 6, 2011
            
            [0.6.7]: https://github.com/lsegal/yard/compare/v0.6.6...v0.6.7
            
            - Fix has_rdoc gem specification issue with new RubyGems plugin API (oops!)
            
            # [0.6.6] - April 6, 2011
            
            [0.6.6]: https://github.com/lsegal/yard/compare/v0.6.5...v0.6.6
            
            - 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
            
            # [0.6.5] - March 13, 2011
            
            [0.6.5]: https://github.com/lsegal/yard/compare/v0.6.4...v0.6.5
            
            - 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)
            
            # [0.6.4] - December 21, 2010
            
            [0.6.4]: https://github.com/lsegal/yard/compare/v0.6.3...v0.6.4
            
            - 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)
            
            # [0.6.3] - November 21, 2010
            
            [0.6.3]: https://github.com/lsegal/yard/compare/v0.6.2...v0.6.3
            
            - Fixed regression that caused `yardoc --markup` to silently exit
            
            # [0.6.2] - November 15, 2010
            
            [0.6.2]: https://github.com/lsegal/yard/compare/v0.6.1...v0.6.2
            
            - **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)
            
            # [0.6.1] - September 06, 2010
            
            [0.6.1]: https://github.com/lsegal/yard/compare/v0.6.0...v0.6.1
            
            - 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
            
            # [0.6.0] - August 29, 2010
            
            [0.6.0]: https://github.com/lsegal/yard/compare/v0.5.8...v0.6.0
            
            - 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}
            
            # [0.5.8] - June 22, 2010
            
            [0.5.8]: https://github.com/lsegal/yard/compare/v0.5.7...v0.5.8
            
            - Merge fix from 0.6 branch for --no-private visibility checking
            
            # [0.5.7] - June 21, 2010
            
            [0.5.7]: https://github.com/lsegal/yard/compare/v0.5.6...v0.5.7
            
            - 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
            
            # [0.5.6] - June 12, 2010
            
            [0.5.6]: https://github.com/lsegal/yard/compare/v0.5.5...v0.5.6
            
            - Bug fixes for RubyGems plugin, `has_rdoc=false` should now work
            - New API for registering custom parsers. See {file:docs/WhatsNew.md}
            
            # [0.5.5] - May 22, 2010
            
            [0.5.5]: https://github.com/lsegal/yard/compare/v0.5.4...v0.5.5
            
            - Various bug fixes
            
            # [0.5.4] - March 22, 2010
            
            [0.5.4]: https://github.com/lsegal/yard/compare/v0.5.3...v0.5.4
            
            - See {file:docs/WhatsNew.md what's new document} for changes
            
            # [0.5.3] - January 11, 2010
            
            [0.5.3]: https://github.com/lsegal/yard/compare/v0.5.2...v0.5.3
            
            - See {file:docs/WhatsNew.md what's new document} for changes
            
            # [0.5.2] - December 16, 2009
            
            [0.5.2]: https://github.com/lsegal/yard/compare/v0.5.1...v0.5.2
            
            - See {file:docs/WhatsNew.md what's new document} for changes
            
            # [0.5.1] - December 15, 2009
            
            [0.5.1]: https://github.com/lsegal/yard/compare/v0.5.0...v0.5.1
            
            - See {file:docs/WhatsNew.md what's new document} for changes
            
            # [0.5.0] - December 13, 2009
            
            [0.5.0]: https://github.com/lsegal/yard/compare/v0.4.0...v0.5.0
            
            - See {file:docs/WhatsNew.md what's new document} for changes
            
            # [0.4.0] - November 15, 2009
            
            [0.4.0]: https://github.com/lsegal/yard/compare/v0.2.3.5...v0.4.0
            
            - 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}
            
            # [0.2.3.5] - August 13, 2009
            
            [0.2.3.5]: https://github.com/lsegal/yard/compare/v0.2.3.4...v0.2.3.5
            
            - Minor bug fixes.
            
            # [0.2.3.4] - August 07, 2009
            
            [0.2.3.4]: https://github.com/lsegal/yard/compare/v0.2.3.3...v0.2.3.4
            
            - Minor bug fixes.
            
            # [0.2.3.3] - July 26, 2009
            
            [0.2.3.3]: https://github.com/lsegal/yard/compare/v0.2.3.2...v0.2.3.3
            
            - Minor bug fixes.
            
            # [0.2.3.2] - July 06, 2009
            
            [0.2.3.2]: https://github.com/lsegal/yard/compare/v0.2.3.1...v0.2.3.2
            
            - 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
            
            # [0.2.3.1] - June 13, 2009
            
            [0.2.3.1]: https://github.com/lsegal/yard/compare/v0.2.3...v0.2.3.1
            
            - 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.
            
            # [0.2.3] - June 07, 2009
            
            [0.2.3]: https://github.com/lsegal/yard/compare/v0.2.2...v0.2.3
            
            - See the {file:docs/WhatsNew.md} file for a list of important new features.
            
            # [0.2.2] - Jun 16, 2008
            
            [0.2.2]: https://github.com/lsegal/yard/compare/v0.2.1...v0.2.2
            
            - 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.
            
            # [0.2.1] - February 20, 2008
            
            [0.2.1]: https://github.com/lsegal/yard/compare/v0.1a...v0.2.1
            
            - See the {file:docs/WhatsNew.md} file for a list of important new features.
            
            # 0.1a - February 24, 2007
            
            - 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).
            yard-0.9.12/LEGAL0000755000004100000410000000564313206751010013347 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.9.12/README.md0000755000004100000410000003141413206751010014052 0ustar  www-datawww-data# YARD: Yay! A Ruby Documentation Tool
            
            [![Homepage](http://img.shields.io/badge/home-yardoc.org-blue.svg)](http://yardoc.org)
            [![GitHub](http://img.shields.io/badge/github-lsegal/yard-blue.svg)](http://github.com/lsegal/yard)
            [![Documentation](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](http://rubydoc.org/gems/yard/frames)
            
            [![Gem Version](https://badge.fury.io/rb/yard.svg)](http://github.com/lsegal/yard/releases)
            [![Build Status](https://travis-ci.org/lsegal/yard.svg?branch=master)](https://travis-ci.org/lsegal/yard)
            [![Coverage Status](https://coveralls.io/repos/github/lsegal/yard/badge.svg)](https://coveralls.io/github/lsegal/yard)
            [![License](http://img.shields.io/badge/license-MIT-yellowgreen.svg)](#license)
            
            ## 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:
            
            ```ruby
            # 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:
            
            ```ruby
            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:
            
            ```sh
            $ 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:
            
            ```sh
            $ 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:
            
            ```sh
            $ 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:
            
            ```sh
            $ 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 '-'.
            
            ```sh
            $ yardoc 'app/**/*.rb' - README LICENSE FAQ
            ```
            
            If no globs precede the '-' argument, the default glob (`lib/**/*.rb`) is
            used:
            
            ```sh
            $ 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:
            
            ```sh
            --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:
            
            ```sh
            --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`:
            
            ```ruby
            YARD::Rake::YardocTask.new do |t|
             t.files   = ['lib/**/*.rb', OTHER_PATHS]   # optional
             t.options = ['--any', '--extra', '--opts'] # optional
             t.stats_options = ['--list-undoc']         # optional
            end
            ```
            
            All the settings: `files`, `options` and `stats_options` are optional. `files` will default to
            `lib/**/*.rb`, `options` will represents any options you might want
            to add and `stats_options` will pass extra options to the stats command.
            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:
            
            ```sh
            $ 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:
            
            ```sh
            $ 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:
            
            ```sh
            $ 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:
            
            ```sh
            $ 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:
            
            ```sh
            $ 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:
            
            ```sh
            $ yard graph --protected --full --dependencies
            ```
            
            
            ## Changelog
            
            See {file:CHANGELOG.md} for a list of changes.
            
            ## License
            
            YARD © 2007-2016 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.9.12/yard.gemspec0000755000004100000410000000342013206751010015073 0ustar  www-datawww-data# frozen_string_literal: true
            require 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}/**/*") +
                                ['CHANGELOG.md', 'LICENSE', 'LEGAL', 'README.md', 'Rakefile', '.yardopts', __FILE__]
              s.require_paths = ['lib']
              s.executables   = ['yard', 'yardoc', 'yri']
              s.license = 'MIT' if s.respond_to?(:license=)
              s.metadata['yard.run'] = 'yri'
              s.post_install_message = <<-eof
            --------------------------------------------------------------------------------
            As of YARD v0.9.2:
            
            RubyGems "--document=yri,yard" hooks are now supported. You can auto-configure
            YARD to automatically build the yri index for installed gems by typing:
            
                $ yard config --gem-install-yri
            
            See `yard config --help` for more information on RubyGems install hooks.
            
            You can also add the following to your .gemspec to have YARD document your gem
            on install:
            
                spec.metadata["yard.run"] = "yri" # use "yard" to build full HTML docs.
            
            --------------------------------------------------------------------------------
            eof
            end
            
            CityNC