class Sec_file < String def initialize path unless path.instance_of?(String) raise "Sec_file class initialization error: The argument is not String type." end unless File.exist?(path) raise "Sec_file class initialization error: File #{path} is not exist." end unless path =~ /sec\d+(\.\d+)?\.src\.md$/ raise "Sec_file class initialization error: The argment \"#{path}\" doesn't have secXX.src.md form. XX are digits." end @name = File.basename path @dirname = File.dirname path super(path) end def path self end def basename @name end def dirname @dirname end def c_files buf = IO.readlines(self) files = [] in_include = false buf.each do |line| if in_include if line == "@@@\n" in_include = false else files << @dirname+"/"+line.match(/^ *(\S*)/)[1] end elsif line == "@@@include\n" in_include = true else # lines out of @@@include command is thrown away. end end files end def to_md @name.gsub(/\.(src\.md|md|html|tex)$/, ".md") end def to_html @name.gsub(/\.(src\.md|md|html|tex)$/, ".html") end def to_tex @name.gsub(/\.(src\.md|md|html|tex)$/, ".tex") end def num # the return value is String @name.match(/\d+(\.\d+)?/)[0] end def to_f self.num.to_f end def <=> other if other.instance_of?(Sec_file) self.to_f <=> other.to_f else nil end end # Note: is_i? indicates the number is integer mathematically. For example, 2.0 is an integer. # It doesn't mean the class of the number is Integer. def is_i? self.to_f == self.to_f.floor end def renum! n if n.instance_of?(String) n = n.to_i if n =~ /^\d+$/ n = n.to_f if n =~ /^\d+\.\d+/ end if n.instance_of?(Integer) || n.instance_of?(Float) n = n.to_i if n == n.floor old = self new = self.gsub(/\d+(\.\d+)?\.src\.md$/, "#{n}.src.md") if old != new File.rename old, new self.replace new @name = File.basename new @dirname = File.dirname new end end end end class Sec_files < Array def initialize sec_files if sec_files.instance_of? Array sec_files.each do |sec_file| unless sec_file.instance_of? Sec_file raise "#{sec_file} is not an instance of Sec_file." end end super(sec_files) else raise "#{sec_files} is not an array." end end def renum! self.sort! tbl = [] n = 1 self.each do |sec_file| tbl << [ sec_file.num, n, sec_file.to_f == n ? true : false ] n += 1 end while any_diff?(tbl) unless try_renum(tbl) break end end if any_diff?(tbl) raise "Renumbering failed." end end private def any_diff? tbl tbl.find_index { |row| row[2] == false } end def try_renum tbl changed = false (self.size - 1).downto 0 do |i| if tbl[i][2] == false n = tbl[i][1] # number to substitute found = self.find_index { |sec_file| sec_file != self && sec_file.to_f == n } unless found # OK to replace self[i].renum! n tbl[i][2] = true # tbl[0] (old number (String) is kept in the array 'tbl') changed = true self.each do |sec_file| buf = IO.readlines sec_file buf_n = buf.map { |line| line.gsub(/((S|s)ection *)#{tbl[i][0]}/, "\\1#{n}").gsub(/((S|s)ec *)#{tbl[i][0]}/, "\\1#{n}") } IO.write sec_file, buf_n.join end end end end changed end end