Ruby Skript asm.rb
Einerseits möchte man in Ruby wiederverwendbaren Code schreiben, lagert also Klassen in extra Dateien aus, die man dann als Bibliothek nachlädt. Andererseits ist es oft nervig und hinderlich, wenn man mehrere Dateien installieren muss, um ein kleines Skript auf einem Rechner verfügbar zu machen.
Ich hab mir deshalb ein Skript geschrieben, welches alle Quellcode-Dateien zu einer Programmdatei zusammenfügt, die man dann ideal verteilen kann.
Das Konzept: Bei der Entwicklung und beim Test werden wie bisher alle selbstgeschriebenen Klassenbibliotheken mit require in das Anwendungs-Skript geholt. Jedoch werden alle require-Zeilen, die später in eine Datei zusammengefasst werden sollen, mit einem #include markiert.
require 'csv' require 'myclasslib/dbg' #include require 'myclasslib/string_ext' #include # Skriptcode...
Wenn das Skript nun freigegeben ist und verteilt werden soll, assembliert man alle Teile.
ruby asm.rb MeinSkript.rb > MeinSkript
Das asm.rb durchläuft MeinSkript.rb und ersetzt alle require Zeilen, die mit #include markiert sind, durch den Inhalt der Bibliotheks-Dateien. Heraus kommt eine Datei, die den ganzen Code enthält. Es werden sozusagen alle Einzelteile zusammengebaut, ähnlich wie beim statischen Linken bei C-Programmen.
Quellcode asm.rb
Der Quellcode wurde getestet unter Linux und Windows 2000 mit Ruby 1.6.8 und Ruby 1.8.2. Neben der Benutzung also unabhängiges Werkzeug, kann es auch als Bibliothek in ein eigenes Skript eingebunden werden.
Changelog
- 2005/07/28 Shebang Ersetzung
- 2005/02/26 Ersetzung __FILE__ durch Library-Filenamen, abschneiden alles hinter __END__, Code aufgeräumt
- 2005/02/25 Initial Release
Patch: 2005/07/28 Shebang Ersetzung
Das bisherige Skript setzt automatisch eine Default-Shebang-Zeile ein (#!/usr/bin/env ruby). Eine kleine Erweiterung sorgt dafür, dass die Shebang Zeile des Originalskripts genommen wird, falls vorhanden. Die Methode self.insert_file muss wie folgt gepatcht werden:
def self.insert_file( file, root ) error( "File #{file} not found." ) if !File.file?(file) # --- BEGIN Patch # First line Shebang? -> replace default-Shebang if root File.foreach(file) do |firstline| if firstline =~ /^\#\!/ @@out[0] = firstline.chomp end break end end # --- END Patch File.foreach(file) do |line| ...
Version: 2005/02/26
#!/usr/bin/env ruby # Winfried Mueller, www.reintechnisch.de, Copyright, 2004, GPL # Release 2005/02/26 # # asm.rb - assemble the main file and all #include requires to one file # Use: ruby asm.rb infile > out class Asm @@included = Hash.new @@out = Array.new @@header = Array.new def self.clear @@out = Array.new @@included = Hash.new @@header = Array.new end def self.out return @@out end def self.to_s @@out.join( "\n" ) end # insert all required files with #include directive # e.g. require 'mylib/lib1' #include def self.insert_file( file, root ) error( "File #{file} not found." ) if !File.file?(file) File.foreach(file) do |line| # include all lines with '#include' at end of line rxp_req_include = /^\s*require\s*["'](.*?)["']\s*#\s*include/ if line =~ rxp_req_include libfile = $1 # file is already included if @@included[libfile] == true next end # include file @@included[libfile] = true out_begin_require_header( libfile ) libfile_full = find_lib_file( libfile ) || error( "File #{libfile} not found." ) insert_file( libfile_full, false ) out_end_require_header( libfile ) else line.chomp! # replace __FILE__ in included libs # cut all after __END__ in included libs if !root line.gsub!( /__FILE__/, "'" << File.basename( file ) << "'" ) if line =~ /^__END__/ return end end @@out << line end end end # add a line to global header def self.add_header( str ) @@header << str.chomp end # generate global header buffered in @@out def self.out_header @@out << "#!/usr/bin/env ruby" @@out << "#" @@out << "# This file is automatically generated. DO NOT MODIFY!" @@out << "#" @@out << "" @@header.each do |line| @@out << line end end def self.out_begin_require_header( libfile ) @@out << "" @@out << "# ========== begin include #{libfile} ==========" @@out << "" end private_class_method :out_begin_require_header def self.out_end_require_header( libfile ) @@out << "# ========== end include #{libfile} ==========" @@out << "" end private_class_method :out_end_require_header # search in all libdirs for libfile def self.find_lib_file( libfile ) filename_full = nil $:.each do |libdir| f = File.join(libdir, libfile + ".rb") if File.file?( f ) filename_full = f break end end return filename_full end private_class_method :find_lib_file def self.error( msg ) $stderr.puts "Error: " << msg raise msg end private_class_method :error end if __FILE__ == $0 main_file = $*[0] Asm::out_header Asm::insert_file( main_file, true ) puts Asm::to_s exit (0) end
Version: 2005/02/25
#!/usr/bin/env ruby # Winfried Mueller, www.reintechnisch.de, Copyright, 2004, GPL # Release 2005/02/25 # # asm.rb - assemble the main file and all #include requires to one file # Use: ruby asm.rb infile > out class Asm @@included = Hash.new @@out = Array.new @@header = Array.new def self.clear @@out = Array.new @@included = Hash.new @@header = Array.new end def self.out return @@out end def self.to_s @@out.join( "\n" ) end def self.insert_file( file ) File.foreach(file) do |line| file = nil # include all lines with '#include' at end of line if line =~ /^\s*require\s*["'](.*?)["']\s*#\s*include/ file = $1 if @@included[file] == true next end @@included[file] = true @@out << "" @@out << "# ========== begin include #{$1} ==========" @@out << "" included = false $:.each do |libdir| ffile = File.join(libdir, file + ".rb") if File.file?( ffile ) self.insert_file( ffile ) included = true break end end if !included $stderr.puts "File #{file} not found." raise end @@out << "# ========== end include #{file} ==========" @@out << "" else @@out << line.chomp end end end def self.add_header( str ) @@header << str.chomp end def self.out_header @@out << "#!/usr/bin/env ruby" @@out << "#" @@out << "# This file is automatically generated. DO NOT MODIFY!" @@out << "#" @@out << "" @@header.each do |line| @@out << line end end end if __FILE__ == $0 main_file = $*[0] if !File.file?(main_file) $stderr.puts "Error: Can't find file #{main_file}" exit (-1) end Asm::out_header Asm::insert_file( main_file ) puts Asm::to_s exit (0) end