diff --git a/data/bitclust/template/class b/data/bitclust/template/class index b4f3afbb..d179183b 100644 --- a/data/bitclust/template/class +++ b/data/bitclust/template/class @@ -30,6 +30,20 @@ <% unless @entry.aliases.empty? %>
aliases: <%=h @entry.aliases.map{|c| c.name}.join(', ') %> <% end %> +<% unless @entry.dynamically_included.empty? %> +
dynamic include: + <%= @entry.dynamically_included.map{|m| + class_link(m.name) + " (by " + library_link(m.library.name) + ")" + }.join(", ") + %> +<% end %> +<% unless @entry.dynamically_extended.empty? %> +
dynamic extend: + <%= @entry.dynamically_extended.map{|m| + class_link(m.name) + " (by " + library_link(m.library.name) + ")" + }.join(", ") + %> +<% end %>

<% headline_push diff --git a/lib/bitclust/classentry.rb b/lib/bitclust/classentry.rb index 554d9e29..6dc6b034 100644 --- a/lib/bitclust/classentry.rb +++ b/lib/bitclust/classentry.rb @@ -81,6 +81,8 @@ def labels property :superclass, 'ClassEntry' property :included, '[ClassEntry]' property :extended, '[ClassEntry]' + property :dynamically_included, '[ClassEntry]' + property :dynamically_extended, '[ClassEntry]' property :library, 'LibraryEntry' property :aliases, '[ClassEntry]' property :aliasof, 'ClassEntry' @@ -142,6 +144,24 @@ def extend(m) extended().push m end + # Add a module +m+ to the dynamically included module list. + def dynamic_include(m, lib) + if m.library != lib + message = "dynamically included module #{m.name} should be defined in the module #{lib.name}" + raise InvalidLibrary, message + end + dynamically_included().push m + end + + # Add a module +m+ to the dynamically extended module list. + def dynamic_extend(m, lib) + if m.library != lib + message = "dynamically extended module #{m.name} should be defined in the module #{lib.name}" + raise InvalidLibrary, message + end + dynamically_extended().push m + end + # Add a alias +c+ to the alias list. def alias(c) aliases().push c diff --git a/lib/bitclust/exception.rb b/lib/bitclust/exception.rb index 5e069f24..33b023d1 100644 --- a/lib/bitclust/exception.rb +++ b/lib/bitclust/exception.rb @@ -17,6 +17,7 @@ class ParseError < DocumentError; end class WrongInclude < DocumentError; end class InvalidLink < DocumentError; end class InvalidAncestor < DocumentError; end + class InvalidLibrary < DocumentError; end class UserError < Error; end class InvalidDatabase < UserError; end class InvalidKey < UserError; end diff --git a/lib/bitclust/rrdparser.rb b/lib/bitclust/rrdparser.rb index adb398f9..0695fbe1 100644 --- a/lib/bitclust/rrdparser.rb +++ b/lib/bitclust/rrdparser.rb @@ -194,15 +194,21 @@ def read_aliases(f) def read_includes(f, reopen = false) f.while_match(/\Ainclude\s/) do |line| - tty_warn "#{line.location}: dynamic include is not implemented yet" if reopen - @context.include line.split[1] unless reopen # FIXME + if reopen + @context.dynamic_include(line.split[1]) + else + @context.include(line.split[1]) + end end end def read_extends(f, reopen = false) f.while_match(/\Aextend\s/) do |line| - tty_warn "#{line.location}: dynamic extend is not implemented yet" if reopen - @context.extend line.split[1] unless reopen # FIXME + if reopen + @context.dynamic_extend(line.split[1]) + else + @context.extend(line.split[1]) + end end end @@ -403,6 +409,14 @@ def extend(name) @klass.extend @db.get_class(name) end + def dynamic_include(name) + @klass.dynamic_include(@db.get_class(name), @library) + end + + def dynamic_extend(name) + @klass.dynamic_extend(@db.get_class(name), @library) + end + # Add a alias +name+ to the alias list. def alias(name) @db.open_class(name) do |c| diff --git a/test/test_methoddatabase.rb b/test/test_methoddatabase.rb index 4546a94e..ba5a3b48 100644 --- a/test/test_methoddatabase.rb +++ b/test/test_methoddatabase.rb @@ -50,12 +50,25 @@ def test_search_methods__constant assert_equal 'AAA', result.records.first.entry.name end + def test_dynamic_include + assert_equal(["BazA"], + @db.get_class("A").dynamically_included.map{|m| m.name}) + assert_equal(["BazB"], + @db.get_class("B").dynamically_included.map{|m| m.name}) + end + private def setup_files FileUtils.mkdir_p("#{@root}/_builtin") + File.open("#{@root}/LIBRARIES", 'w+') do |file| file.puts '_builtin' + file.puts 'dyn_include_open_a' + file.puts 'dyn_include_reopen_a' + file.puts 'dyn_include_reopen_b' + file.puts 'dyn_include_open_b' end + File.open("#{@root}/_builtin.rd", 'w+') do |file| file.puts <<'HERE' description @@ -77,5 +90,25 @@ def setup_files HERE end + + File.open("#{@root}/dyn_include_open_a.rd", 'w+') do |file| + file.puts "= class A" + end + + File.open("#{@root}/dyn_include_reopen_a.rd", 'w+') do |file| + file.puts "= module BazA" + file.puts "= reopen A" + file.puts "include BazA" + end + + File.open("#{@root}/dyn_include_open_b.rd", 'w+') do |file| + file.puts "= class B" + end + + File.open("#{@root}/dyn_include_reopen_b.rd", 'w+') do |file| + file.puts "= module BazB" + file.puts "= reopen B" + file.puts "include BazB" + end end end