Class: CGenerator::Library

Inherits:
Template show all
Defined in:
lib/cgen/cgen.rb

Direct Known Subclasses

CShadow::Library

Defined Under Namespace

Classes: CommitError, RbDefineAccumulator, RbDefineAllocAccumulator

Instance Attribute Summary collapse

Attributes inherited from Accumulator

#name, #parent

Instance Method Summary collapse

Methods inherited from Template

accumulator

Methods inherited from Accumulator

#accept?, #add, #add_one, #add_one_really, #inspect, #inspect_one, #output, #output_one, #separator, #to_s

Constructor Details

#initialize(name) ⇒ Library

Returns a new instance of Library.



605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
# File 'lib/cgen/cgen.rb', line 605

def initialize name
  super name
  
  @show_times_flag = @purge_source_dir = false
  @committed = false
  @source_file = nil
  @include_dirs = []
  
  @rtime = Time.now.to_f
  @ptime = process_times

  unless name =~ /\A[A-Za-z_]\w*\z/
    raise NameError,
      "\n  Not a valid library name: '#{name}'." +
      "\n  Name must be a C identifier."
  end
  
  @include_file, @source_file = add_file "libmain"
  @include_file.include '<ruby.h>'
  
  @init_library_function = define_c_function "Init_" + name
  @init_library_function.scope :extern
  
  @init_library_function.body     \
      rb_define_method!,
      rb_define_module_function!,
      rb_define_global_function!,
      rb_define_singleton_method!,
      rb_define_alloc_func!
    ## odd, putting an accum inside
    ## a template which is not the parent
end

Instance Attribute Details

#include_dirsObject (readonly)

Array of dirs which will be searched for extra include files. Example:

lib.include_dirs << "/home/me/include"


603
604
605
# File 'lib/cgen/cgen.rb', line 603

def include_dirs
  @include_dirs
end

#include_fileObject (readonly)

Returns the template for the main include file of the library. Usually, there is no need to access this directly.



580
581
582
# File 'lib/cgen/cgen.rb', line 580

def include_file
  @include_file
end

#init_library_functionObject (readonly)

Returns a Function template object. This function is called when the library is loaded. Method definitions put stuff here to register methods with Ruby. Usually, there is no need to bother this guy directly. Use Library#setup instead.



576
577
578
# File 'lib/cgen/cgen.rb', line 576

def init_library_function
  @init_library_function
end

#purge_source_dirObject

The #purge_source_dir attribute controls what happens to .c, .h, and .o files in the source dir of the library that are not among those generated as part of the library. If this is set to :delete, then those files are deleted. Other true values cause the .c, .h, and .o files to be renamed with the .hide extension. (Note that this makes it difficult to keep manually written C files in the same dir.) False flag values (the default) cause CGen to leave the files untouched.

Note that, regardless of this setting, #mkmf will construct a Makefile which lists all .c files that are in the source dir. If you do not delete obsolete files, they will be compiled into your library!



599
600
601
# File 'lib/cgen/cgen.rb', line 599

def purge_source_dir
  @purge_source_dir
end

#show_times_flagObject

Returns the value of attribute show_times_flag.



586
587
588
# File 'lib/cgen/cgen.rb', line 586

def show_times_flag
  @show_times_flag
end

#source_fileObject (readonly)

Returns the template for the main source file of the library. Usually, there is no need to access this directly.



584
585
586
# File 'lib/cgen/cgen.rb', line 584

def source_file
  @source_file
end

Instance Method Details

#add_file(name, opts = {}) ⇒ Object

Creates templates for two files, a source (.c) file and an include (.h) file that will be generated in the same dir as the library. The base file name is taken from the argument. Returns an array containing the include file template and the source file template, in that order.

Functions can be added to the source file by calling #define_method and similar methods on the source file template. Their rb_init calls are done in #init_library_function in the main library source file. The new source file automatically #includes the library’s main header file, as well as its own header file, and the library’s main source file also #includes the new header file. Declarations can be added to the header file by calling #declare on it, but in many cases this is taken care of automatically.



665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
# File 'lib/cgen/cgen.rb', line 665

def add_file name, opts = {}
  pair = @pile.detect {|p| p[0].name == name + ".h"}

  if not pair
    new_include_file = CFile.new name + ".h", self
    new_source_file = CFile.new name + ".c", self, new_include_file

    if @source_file
      new_source_file.include @include_file unless opts[:independent]
      @source_file.include new_include_file
    end
    new_source_file.include new_include_file

    pair = [new_include_file, new_source_file]
    add pair     # for inspect and commit
  end
  
  return pair
end

#after_commit(&block) ⇒ Object

Schedules block to run after Library#commit. The before blocks are run in the same order in which they were scheduled; the after blocks run in the reverse order (analogously with BEGIN/END). Each block is evaluated in the context in which it was created (instance_eval is not used), and it is passed the library as an argument.



715
716
717
# File 'lib/cgen/cgen.rb', line 715

def after_commit(&block)
  (@after_commit ||= []) << block
end

#assert_uncommittedObject



685
686
687
688
689
# File 'lib/cgen/cgen.rb', line 685

def assert_uncommitted
  if @committed
    raise CommitError, "\nLibrary #{@name} has already been committed."
  end
end

#before_commit(&block) ⇒ Object

Schedules block to run before Library#commit. The before blocks are run in the same order in which they were scheduled; the after blocks run in the reverse order (analogously with BEGIN/END). Each block is evaluated in the context in which it was created (instance_eval is not used), and it is passed the library as an argument.



706
707
708
# File 'lib/cgen/cgen.rb', line 706

def before_commit(&block)
  (@before_commit ||= []) << block
end

#build_wrapperObject



1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
# File 'lib/cgen/cgen.rb', line 1016

def build_wrapper
  if File.exists? @name
    unless File.directory? @name
      raise CommitError, "Library #{@name}: Can't mkdir; file exists."
    end
  else
    Dir.mkdir @name
  end
  
  Dir.chdir @name do yield end
    ### this is fragile--should record abs path when Lib is created
end

#commit(build = true) ⇒ Object

Writes the files to disk, and makes and loads the library.

Note that #commit must be called after all C code definitions for the library, but before instantiation of any objects that use those definitions. If a definition occurs after commit, or if instantiation occurs before commit, then a CGenerator::Library::CommitError is raised, with an appropriate message. Sometimes, this forces you to use many small libraries, each committed just in time for use. See examples/fixed-array.rb.



727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
# File 'lib/cgen/cgen.rb', line 727

def commit(build = true)
  assert_uncommitted
  
  while @before_commit
    bc = @before_commit; @before_commit = nil
    bc.each {|block| block[self]}
  end

  @committed = true

  if build
    @logname ||= "make.log"

    show_times "precommit"       
    show_times "write"       do write       end
    show_times "makedepend"  do makedepend  end
    show_times "mkmf"        do mkmf        end
    show_times "make"        do make        end
  end
  
  show_times "loadlib"     do loadlib     end

  while @after_commit
    ac = @after_commit; @after_commit = nil
    ac.reverse.each {|block| block[self]}
  end
end

#committed?Boolean

True if the library has been committed.

Returns:

  • (Boolean)


692
693
694
# File 'lib/cgen/cgen.rb', line 692

def committed?
  @committed
end

#declare(*args) ⇒ Object Also known as: declare_static

call-seq:

declare :x => "int x", ...
declare_extern :x => "int x", ...

Puts the string in the declaration area of the .c or .h file, respectively. The declaration area is before the function definitions, and after the structure declarations.



1203
1204
1205
# File 'lib/cgen/cgen.rb', line 1203

def declare(*args)
  @source_file.declare(*args)
end

#declare_extern(*args) ⇒ Object



1208
1209
1210
# File 'lib/cgen/cgen.rb', line 1208

def declare_extern(*args)
  @include_file.declare(*args)
end

#declare_extern_struct(struct_name, *rest) ⇒ Object

See #declare_struct.



1224
1225
1226
# File 'lib/cgen/cgen.rb', line 1224

def declare_extern_struct struct_name, *rest
  @include_file.declare_struct struct_name, *rest
end

#declare_module(mod, cfile = nil) ⇒ Object Also known as: declare_class

call-seq:

declare_class cl
declare_module mod
declare_symbol sym

Define a C variable which will be initialized to refer to the class, module, or symbol. These accumulators return the name of the C variable which will be generated and initialized to the ID of the symbol, and this return value can be interpolated into C calls to the Ruby API. (The arguments are the actual Ruby objects.) This is very useful in #rb_ivar_get/#rb_ivar_set calls, and it avoids doing the lookup more than once:

...
declare :my_ivar => "VALUE my_ivar"
body %{
  my_ivar = rb_ivar_get(shadow->self, #{declare_symbol :@my_ivar});
  rb_ivar_set(shadow->self, #{declare_symbol :@my_ivar}, Qnil);
}

The second declaration notices that the library already has a variable that will be initialized to the ID of the symbol, and uses it.



1259
1260
1261
1262
1263
1264
1265
# File 'lib/cgen/cgen.rb', line 1259

def declare_module mod, cfile = nil
  c_name = "module_#{CGenerator::make_c_name mod.to_s}"
  declare mod => "VALUE #{c_name}"
  (cfile || self).declare_extern mod => "extern VALUE #{c_name}"
  setup mod => "#{c_name} = rb_path2class(\"#{mod}\")"
  c_name.intern
end

#declare_struct(struct_name, *rest) ⇒ Object Also known as: declare_static_struct

call-seq:

declare_struct name, attributes=nil
declare_extern_struct name, attributes=nil

Returns a Structure template, which generates to a typedefed C struct in the .c or .h file. The #declare method of this template is used to add members.



1218
1219
1220
# File 'lib/cgen/cgen.rb', line 1218

def declare_struct struct_name, *rest
  @source_file.declare_struct struct_name, *rest
end

#declare_symbol(sym, cfile = nil) ⇒ Object

See #declare_module.



1269
1270
1271
1272
1273
1274
1275
# File 'lib/cgen/cgen.rb', line 1269

def declare_symbol sym, cfile = nil
  c_name = "ID_#{CGenerator::make_c_name sym}"
  declare sym => "ID #{c_name}"
  (cfile || self).declare_extern sym => "extern ID #{c_name}"
  setup sym => "#{c_name} = rb_intern(\"#{sym}\")"
  c_name.intern
end

#define(*args) ⇒ Object Also known as: define_c_function

call-seq:

define_c_function

Defines a plain ol’ C function. Returns a Function template (see below), or a template of the specified type, if given.



1233
1234
1235
# File 'lib/cgen/cgen.rb', line 1233

def define(*args)
  @source_file.define(*args)
end

#define_c_global_function(*args) ⇒ Object

See #define_c_method.



1176
1177
1178
# File 'lib/cgen/cgen.rb', line 1176

def define_c_global_function(*args)
  @source_file.define_c_global_function(*args)
end

#define_c_method(*args) ⇒ Object

call-seq:

define_c_method mod, name, subclass
define_c_module_function mod, name, subclass
define_c_global_function name, subclass
define_c_singleton_method mod, name, subclass
define_c_class_method mod, name, subclass

Defines a function of the specified name and type in the given class/module (or in the global scope), and returns the function template (often used with #instance_eval to add arguments, code, etc.). The subclass argument is optional and allows the template to belong to a subclass of the function template it would normally belong to.

For example,

define_c_method String, "reverse"

The arguments accepted by the method automatically include self. By default, arguments are passed as individual C arguments, but the can be passed in a Ruby or C array. The latter has the advantage of argument parsing (based on rb_scan_args), defaults, and typechecking. See Method#c_array_args. #define_c_class_method is just an alias for #define_c_singleton_method.



1166
1167
1168
# File 'lib/cgen/cgen.rb', line 1166

def define_c_method(*args)
  @source_file.define_c_method(*args)
end

#define_c_module_function(*args) ⇒ Object

See #define_c_method.



1171
1172
1173
# File 'lib/cgen/cgen.rb', line 1171

def define_c_module_function(*args)
  @source_file.define_c_module_function(*args)
end

#define_c_singleton_method(*args) ⇒ Object Also known as: define_c_class_method

See #define_c_method.



1181
1182
1183
# File 'lib/cgen/cgen.rb', line 1181

def define_c_singleton_method(*args)
  @source_file.define_c_singleton_method(*args)
end

#empty?Boolean

True if no content has been added to the library.

Returns:

  • (Boolean)


697
698
699
# File 'lib/cgen/cgen.rb', line 697

def empty?
  @init_library_function.empty?  ## is this enough?
end

#extconf {|a| ... } ⇒ Object

Override #extconf if you want to do more than just #create_makefile. Note that #create_makefile recognizes all .c files in the library directory, and generates a makefile that compiles them and links them into the dynamic library.

Yields the array of lines being constructed so that additional configuration can be added. See the ruby documentation on mkmf.

Yields:

  • (a)


1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
# File 'lib/cgen/cgen.rb', line 1036

def extconf # :yields: lines_array
  a = []
  a << "require 'mkmf'"
  a << "$CFLAGS = \"#$CFLAGS\"" if defined?($CFLAGS)
  include_dirs.each do |dir|
    a << %{$INCFLAGS << " -I#{dir}"}
  end
  yield a if block_given?
  a << "create_makefile '#{@name}'"
end

#include(*args) ⇒ Object

call-seq:

include "file1.h", "<file2.h>", ...

Insert the include statement(s) at the top of the library’s main .c file. For convenience, <ruby.h> is included automatically, as is the header file of the library itself.



1192
1193
1194
# File 'lib/cgen/cgen.rb', line 1192

def include(*args)
  @source_file.include(*args)
end

#libraryObject



1310
1311
1312
# File 'lib/cgen/cgen.rb', line 1310

def library
  self
end

#literal_symbol(sym, cfile = nil) ⇒ Object

Like Library#declare_symbol, but converts the ID to a VALUE at library initialization time. Useful for looking up hash values keyed by symbol objects, for example. sym is a string or symbol.



1280
1281
1282
1283
1284
1285
1286
# File 'lib/cgen/cgen.rb', line 1280

def literal_symbol sym, cfile = nil
  c_name = "SYM_#{CGenerator::make_c_name sym}"
  declare sym => "VALUE #{c_name}"
  (cfile || self).declare_extern sym => "extern VALUE #{c_name}"
  setup sym => "#{c_name} = ID2SYM(rb_intern(\"#{sym}\"))"
  c_name.intern
end

#loadlibObject



1047
1048
1049
1050
1051
# File 'lib/cgen/cgen.rb', line 1047

def loadlib
  require File.join(".", @name, @name)
rescue ScriptError, StandardError => e
  raise e.class, "\nCgen: problem loading library:\n" + e.message
end

#make(arg = nil) ⇒ Object

use -j and -l make switches for multiprocessor builds (man sysconf) see www.gnu.org/manual/make/html_chapter/make_5.html#SEC47



981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
# File 'lib/cgen/cgen.rb', line 981

def make arg = nil
  build_wrapper do
    unless system "#{make_program} #{arg} >>#{@logname} 2>&1"
      raise CommitError,
        "\n  Make #{arg} failed for #{@name}." +
        "\n  Transcript is saved in #{@name}/#{@logname} and follows:" +
        "\n  " + "_" * 60 +
        "\n" + File.read(@logname).tabto(3).gsub(/^  /, " |") +
        "  " + "_" * 60 + "\n"
    end
    
    if arg == 'clean' or arg == 'distclean'
      File.delete(@logname) rescue SystemCallError
      if arg == 'distclean'
        for template in @pile.flatten do
          File.delete(template.name) rescue SystemCallError
        end
      end
    end
  end
end

#make_programObject



1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
# File 'lib/cgen/cgen.rb', line 1003

def make_program
  case RUBY_PLATFORM
  when /mswin/i
    "nmake"
  when /mingw/i
    "make"
    # "mingw32-make" is the MSYS-independent, MSVC native version
    # which is supposedly less useful
  else
    "make"
  end
end

#makedependObject



892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
# File 'lib/cgen/cgen.rb', line 892

def makedepend
  return if /mswin/i =~ RUBY_PLATFORM ## what else can we do?
  build_wrapper do
    cpat = "*.c"
    chpat = "*.[ch]"
    dep = "depend"
    return if Dir[cpat].all? {|f| test ?<, f, dep}
    
    cfg = RbConfig::CONFIG
    dirs = [cfg["sitearchdir"], cfg["archdir"], cfg["includedir"], *include_dirs]
    
    case cfg["CC"]
    when /gcc/
      makedepend_cmd =
        "#{cfg["CC"]} -MM #{cpat} -I#{dirs.join " -I"} >#{dep} 2>#{@logname}"
    
    else
      makedepend_cmd =
        "touch #{dep} && \
        makedepend -f#{dep} #{cpat} -I#{dirs.join " -I"} >#{@logname} 2>&1"
    end

    result = system makedepend_cmd

    unless result
      log_data = File.read(@logname) rescue nil
      msg = "\n  `#{makedepend_cmd}` failed for #{@name}."
      if log_data
        msg <<
          "\n  Transcript is saved in #{@name}/#{@logname} and follows:" +
          "\n  " + "_" * 60 +
          "\n" + log_data.tabto(3).gsub(/^  /, " |") +
          "  " + "_" * 60 + "\n"
      else
        msg <<
          "\n  No log available.\n"
      end
      raise CommitError, msg
    end
  end
end

#mkmfObject



934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
# File 'lib/cgen/cgen.rb', line 934

def mkmf
  need_to_make_clean = false
  
  # Need to do this in a separate process because mkmf.rb pollutes
  # the global namespace.
  build_wrapper do
    require 'rbconfig'
    ruby = RbConfig::CONFIG["RUBY_INSTALL_NAME"]
    
    old_contents = File.read("extconf.rb") rescue nil
    contents = extconf
    require 'stringio'
    s = StringIO.new
    s.puts(contents)
    s.rewind
    contents = s.read
    
    if old_contents != contents
      File.open("extconf.rb", "w") do |f|
        f.puts contents
      end
      need_to_make_clean = true
    end
    
    ## it would be better to capture the output of extconf.rb before
    ## it writes it to Makefile, but mkmf.rb is not written that way :(
    if File.exist?("Makefile")
      old_makefile = File.read("Makefile")
      require 'fileutils'
      FileUtils.mv("Makefile", "Makefile.old")
    end
    
    system %{
      #{ruby} extconf.rb > #{@logname}
    }
    
    if old_makefile and old_makefile == File.read("Makefile")
      FileUtils.rm("Makefile")
      FileUtils.mv("Makefile.old", "Makefile")
    end
  end
  
  make "clean" if need_to_make_clean
end


852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
# File 'lib/cgen/cgen.rb', line 852

def print_update_reason template, template_str, file_data
  puts "\nUpdating file #{template.name}"
  
  if file_data == nil
    puts "File on disk is empty"
    return
  end
  
  s = file_data
  t = template_str
  slines = s.split "\n"
  tlines = t.split "\n"
  i = 0
  sline = slines[i]
  tline = tlines[i]
  catch :done do
    while sline and tline
      if sline != tline
        puts "Line #{i+1}",
             "On disk:    #{sline.inspect}",
             "In memory:  #{tline.inspect}",
             ""
        throw :done
      end
      i += 1
      sline = slines[i]
      tline = tlines[i]
    end
    if sline == nil and tline == nil
      puts "Very strange, no difference found!"
    else
      if slines.size > tlines.size
        puts "file on disk is longer"
      else
        puts "file in memory is longer"
      end
    end
  end
end

#process_timesObject


:section: Build methods

Methods used during commit to control the build chain. In sequence, #commit calls these methods:

* #write       dumps each file template to disk, if needed
* #makedepend  executes +makedepend+
* #mkmf        calls Library#extconf
* #make        executes the system's +make+ program
* #loadlib     load the library that has been built

These methods can be overridden, but are more typically called via commit or sometimes directly. The argument to #make is interpolated into the system call as a command line argument to the make program. If the argument is ‘clean’ or ‘distclean’ then the make log is deleted; if the argument is ‘distclean’ then all .c and .h files generated by #write are deleted (additional user-supplied .c and .h files in the library dir are not affected).




776
777
778
# File 'lib/cgen/cgen.rb', line 776

def process_times
  RUBY_VERSION.to_f >= 1.7 ? Process.times : Time.times
end

#setup(*args) ⇒ Object

call-seq:

setup key => "statements", ...

Inserts code in the #init_library_function, which is called when the library is loaded. The key is used for redundancy checking, as in the #declare accumulators. Note that hashes are unordered, so constructs like

setup :x => "...", :y => "..."

can result in unpredictable order. To avoid this, use several #setup calls.



1298
1299
1300
# File 'lib/cgen/cgen.rb', line 1298

def setup(*args)
  @init_library_function.setup(*args)
end

#show_times(message) ⇒ Object

If the attribute #show_times_flag is set to true, print the user and system times (and child user and child system on some platforms) and real time for each major step of the commit process. Display message.



783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
# File 'lib/cgen/cgen.rb', line 783

def show_times message
  yield if block_given?
  if @show_times_flag
    unless @show_times_started
      printf "\n%20s %6s %6s %6s %6s %7s\n",
        "__step__", "utime", "stime", "cutime", "cstime", "real"
      @show_times_started = true
    end
    ptime = self.process_times
    rtime = Time.now.to_f
    printf "%20s %6.2f %6.2f %6.2f %6.2f %7.3f\n", message,
      ptime.utime - @ptime.utime, ptime.stime - @ptime.stime,
      ptime.cutime - @ptime.cutime, ptime.cstime - @ptime.cstime,
      rtime - @rtime
    @ptime = ptime
    @rtime = rtime
  end
end

#update_file(f, template) ⇒ Object

Called by write on each .c and .h file to actually write template to the open file f. The default behavior is to compare the existing data with the generated data, and leave the file untouched if nothing changed. Subclasses may have more efficient ways of doing this. (For instance, check a version indicator in the file on disk, perhaps stored using the file’s preamble accumulator. It is even possible to defer some entries in the template until after this check has been made: code that only needs to be regenerated if some specification has changed)



839
840
841
842
843
844
845
846
847
848
849
850
# File 'lib/cgen/cgen.rb', line 839

def update_file f, template
  template_str = template.to_s
  file_data = f.gets(nil) ## sysread is faster?
  unless file_data == template_str
    if defined?($CGEN_VERBOSE) and $CGEN_VERBOSE
      print_update_reason(template, template_str, file_data)
    end
    f.rewind
    f.print template_str
    f.truncate f.pos
  end
end

#use_work_dir(dir_name) ⇒ Object

Changes into dir_name, creating it first if necessary. Does nothing if already in a directory of that name. Often used with “tmp”.



640
641
642
643
644
645
646
647
648
649
650
# File 'lib/cgen/cgen.rb', line 640

def use_work_dir dir_name
  if File.basename(Dir.pwd) == dir_name
    yield
  else
    require 'fileutils'
    FileUtils.makedirs dir_name
    Dir.chdir dir_name do
      yield
    end
  end
end

#writeObject



802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
# File 'lib/cgen/cgen.rb', line 802

def write
  build_wrapper do
    templates = @pile.flatten.sort_by { |t| t.name }
    
    if @purge_source_dir
      # hide or delete files not listed in templates
      files = Dir["*.{c,h,o}"]
      template_files = templates.map { |t| t.name }
      template_files += 
        template_files.grep(/\.c$/).map { |f| f.sub(/\.c$/, ".o") }
      for file in files - template_files
        if @purge_source_dir == :delete
          File.delete(file) rescue SystemCallError
        else
          File.rename(file, file + ".hide") rescue SystemCallError
        end
      end
    end
    
    for template in templates do
      begin
        File.open(template.name, 'r+') {|f| update_file f, template}
      rescue SystemCallError
        File.open(template.name, 'w+') {|f| update_file f, template}
      end
    end
  end
end