@@ -20,15 +20,21 @@ def create
2020 private
2121
2222 def copy_template_structure
23+ # Get list of all files/directories BEFORE creating the target directory
24+ # This prevents infinite recursion when the target gets created
25+ source_items = Dir . glob ( "#{ @source_root } /*" , File ::FNM_DOTMATCH ) . map do |path |
26+ filename = File . basename ( path )
27+ next if skip_file? ( filename )
28+ { source : path , filename : filename }
29+ end . compact
30+
31+ # Now create the target directory
2332 FileUtils . mkdir_p ( @gem_name )
2433
25- # Copy all files except those we want to exclude
26- Dir . glob ( "#{ @source_root } /*" , File ::FNM_DOTMATCH ) . each do |source_path |
27- filename = File . basename ( source_path )
28-
29- # Skip files we don't want to copy
30- next if skip_file? ( filename )
31-
34+ # Copy the pre-determined list of files
35+ source_items . each do |item |
36+ source_path = item [ :source ]
37+ filename = item [ :filename ]
3238 dest_path = File . join ( @gem_name , filename )
3339
3440 if File . directory? ( source_path )
@@ -47,15 +53,27 @@ def skip_file?(filename)
4753 '..'
4854 ]
4955
50- # Skip any directory that looks like a generated gem (has a .gemspec file)
51- if File . directory? ( File . join ( @source_root , filename ) )
52- gemspec_pattern = File . join ( @source_root , filename , "*.gemspec" )
53- if Dir . glob ( gemspec_pattern ) . any?
56+ return true if excluded_files . include? ( filename )
57+
58+ # Skip any directory that looks like a generated gem
59+ file_path = File . join ( @source_root , filename )
60+ if File . directory? ( file_path )
61+ # Skip if it has a gemspec file that's not the main gemplate.gemspec
62+ gemspec_files = Dir . glob ( File . join ( file_path , "*.gemspec" ) )
63+ if gemspec_files . any? && !gemspec_files . include? ( File . join ( file_path , "gemplate.gemspec" ) )
64+ return true
65+ end
66+
67+ # Skip if it looks like a previously generated gem directory
68+ if filename != 'lib' && filename != 'spec' &&
69+ ( File . exist? ( File . join ( file_path , "#{ filename } .gemspec" ) ) ||
70+ File . exist? ( File . join ( file_path , "lib" , filename ) ) ||
71+ File . exist? ( File . join ( file_path , "lib" , "#{ filename } .rb" ) ) )
5472 return true
5573 end
5674 end
5775
58- excluded_files . include? ( filename )
76+ false
5977 end
6078
6179 def copy_directory ( source_dir , dest_dir )
@@ -116,24 +134,14 @@ def transform_file_contents
116134 # Clean up files that shouldn't be in generated gems
117135 cleanup_unwanted_files
118136
119- # Transform gemspec
120- transform_gemspec
121-
122- # Transform main lib file
123- transform_main_lib_file
137+ # Remove CLI-specific files
138+ remove_cli_files
124139
125- # Transform version file
126- transform_version_file
140+ # Apply global transformations to all text files
141+ transform_all_files
127142
128- # Transform spec files
129- transform_spec_helper
130- transform_spec_file
131-
132- # Transform README
133- transform_readme
134-
135- # Transform LICENSE
136- transform_license
143+ # Create new README since the original is gemplate-specific
144+ create_generic_readme
137145 end
138146
139147 def cleanup_unwanted_files
@@ -158,86 +166,97 @@ def cleanup_unwanted_files
158166 end
159167 end
160168 end
161-
162- def transform_gemspec
163- gemspec_file = File . join ( @gem_name , "#{ @gem_name } .gemspec" )
164- return unless File . exist? ( gemspec_file )
165-
166- content = File . read ( gemspec_file )
167- content . gsub! ( /require_relative 'lib\/ gemplate\/ version'/ , "require_relative 'lib/#{ @snake_name } /version'" )
168- content . gsub! ( /spec\. name\s *=\s *'gemplate'/ , "spec.name = '#{ @gem_name } '" )
169- content . gsub! ( /Gemplate::VERSION/ , "#{ @module_name } ::VERSION" )
170- content . gsub! ( /spec\. summary\s *=.*/ , "spec.summary = 'Write a short summary for your gem'" )
171- content . gsub! ( /spec\. description\s *=.*/ , "spec.description = 'Write a longer description for your gem'" )
172- content . gsub! ( /spec\. homepage\s *=.*/ , "spec.homepage = \" https://github.com/yourusername/#{ @gem_name } \" " )
173- content . gsub! ( /spec\. authors\s *=.*/ , "spec.authors = ['Your Name']" )
174- content . gsub! ( /spec\. email\s *=.*/ , "spec.email = ['your.email@example.com']" )
175- content . gsub! ( /spec\. executables\s *=.*/ , "spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }" )
176-
177- File . write ( gemspec_file , content )
178- end
179-
180- def transform_main_lib_file
181- lib_file = File . join ( @gem_name , 'lib' , "#{ @snake_name } .rb" )
182- return unless File . exist? ( lib_file )
183-
184- content = File . read ( lib_file )
185- content . gsub! ( /require_relative 'gemplate\/ / , "require_relative '#{ @snake_name } /" )
186- content . gsub! ( /module Gemplate/ , "module #{ @module_name } " )
187-
188- # Remove CLI-specific requires since this won't be a CLI gem
189- content . gsub! ( /require_relative '#{ @snake_name } \/ cli'\n / , "" )
190- content . gsub! ( /require_relative '#{ @snake_name } \/ generator'\n / , "" )
191-
192- # Remove CLI-specific files that shouldn't be in generated gems
193- cli_file = File . join ( @gem_name , 'lib' , @snake_name , 'cli.rb' )
194- generator_file = File . join ( @gem_name , 'lib' , @snake_name , 'generator.rb' )
195-
196- File . delete ( cli_file ) if File . exist? ( cli_file )
197- File . delete ( generator_file ) if File . exist? ( generator_file )
169+
170+ def remove_cli_files
171+ cli_files = [
172+ File . join ( @gem_name , 'lib' , @snake_name , 'cli.rb' ) ,
173+ File . join ( @gem_name , 'lib' , @snake_name , 'generator.rb' )
174+ ]
198175
199- File . write ( lib_file , content )
176+ cli_files . each { | file | File . delete ( file ) if File . exist? ( file ) }
200177 end
201178
202- def transform_version_file
203- version_file = File . join ( @gem_name , 'lib' , @snake_name , 'version.rb' )
204- return unless File . exist? ( version_file )
205-
206- content = File . read ( version_file )
207- content . gsub! ( /module Gemplate/ , "module #{ @module_name } " )
179+ def transform_all_files
180+ # Find all text files to transform
181+ text_files = Dir . glob ( "#{ @gem_name } /**/*" , File ::FNM_DOTMATCH ) . select do |file |
182+ File . file? ( file ) && text_file? ( file )
183+ end
208184
209- File . write ( version_file , content )
185+ text_files . each do |file_path |
186+ content = File . read ( file_path )
187+
188+ # Apply all transformations
189+ content = apply_transformations ( content )
190+
191+ File . write ( file_path , content )
192+ end
210193 end
211-
212- def transform_spec_helper
213- spec_helper = File . join ( @gem_name , 'spec' , 'spec_helper.rb' )
214- return unless File . exist? ( spec_helper )
215-
216- content = File . read ( spec_helper )
217- content . gsub! ( /require 'gemplate'/ , "require '#{ @snake_name } '" )
218-
219- File . write ( spec_helper , content )
194+
195+ def text_file? ( file_path )
196+ # Skip some specific binary file extensions
197+ return false if file_path . end_with? ( '.png' , '.jpg' , '.jpeg' , '.gif' , '.ico' , '.zip' , '.tar' , '.gz' )
198+
199+ # Simple check for text files - read first few bytes
200+ begin
201+ File . open ( file_path , 'rb' ) do |file |
202+ chunk = file . read ( 512 )
203+ return false if chunk . nil?
204+ # If it contains null bytes, it's likely binary
205+ return false if chunk . include? ( "\x00 " )
206+ end
207+ true
208+ rescue
209+ false
210+ end
220211 end
221-
222- def transform_spec_file
223- spec_file = File . join ( @gem_name , 'spec' , @snake_name , "#{ @snake_name } _spec.rb" )
224- return unless File . exist? ( spec_file )
212+
213+ def apply_transformations ( content )
214+ # Global find and replace patterns
215+ transformations = {
216+ # Module and class names
217+ 'Gemplate' => @module_name ,
218+
219+ # File paths and requires
220+ "require_relative 'lib/gemplate/" => "require_relative 'lib/#{ @snake_name } /" ,
221+ "require_relative 'gemplate/" => "require_relative '#{ @snake_name } /" ,
222+ "require 'gemplate'" => "require '#{ @snake_name } '" ,
223+
224+ # Gem specification
225+ "spec.name = 'gemplate'" => "spec.name = '#{ @gem_name } '" ,
226+ "'gemplate'" => "'#{ @gem_name } '" ,
227+ '"gemplate"' => "\" #{ @gem_name } \" " ,
228+
229+ # URLs and references
230+ 'TwilightCoders/gemplate' => "yourusername/#{ @gem_name } " ,
231+
232+ # Generic placeholders for new gems
233+ /spec\. summary\s *=.*/ => "spec.summary = 'Write a short summary for your gem'" ,
234+ /spec\. description\s *=.*/ => "spec.description = 'Write a longer description for your gem'" ,
235+ /spec\. authors\s *=.*/ => "spec.authors = ['Your Name']" ,
236+ /spec\. email\s *=.*/ => "spec.email = ['your.email@example.com']" ,
237+ /spec\. executables\s *=.*/ => "spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }" ,
238+ /Copyright \( c\) \d + .+/ => "Copyright (c) #{ Time . now . year } Your Name"
239+ }
240+
241+ # Remove CLI-specific requires
242+ content . gsub! ( /require_relative '#{ @snake_name } \/ cli'\n / , "" )
243+ content . gsub! ( /require_relative '#{ @snake_name } \/ generator'\n / , "" )
225244
226- content = File . read ( spec_file )
227- content . gsub! ( /describe Gemplate/ , "describe #{ @module_name } " )
228- content . gsub! ( /Gemplate::VERSION/ , "#{ @module_name } ::VERSION" )
229- content . gsub! ( /Gemplate\. root/ , "#{ @module_name } .root" )
245+ # Apply all transformations
246+ transformations . each do |pattern , replacement |
247+ if pattern . is_a? ( Regexp )
248+ content . gsub! ( pattern , replacement )
249+ else
250+ content . gsub! ( pattern , replacement )
251+ end
252+ end
230253
231- File . write ( spec_file , content )
254+ content
232255 end
233256
234- def transform_readme
257+ def create_generic_readme
235258 readme_file = File . join ( @gem_name , 'README.md' )
236- return unless File . exist? ( readme_file )
237-
238- content = File . read ( readme_file )
239259
240- # Replace the entire README with a generic template
241260 new_content = <<~README
242261 # #{ @module_name }
243262
@@ -281,16 +300,6 @@ def transform_readme
281300 File . write ( readme_file , new_content )
282301 end
283302
284- def transform_license
285- license_file = File . join ( @gem_name , 'LICENSE.txt' )
286- return unless File . exist? ( license_file )
287-
288- content = File . read ( license_file )
289- content . gsub! ( /Copyright \( c\) \d + .+/ , "Copyright (c) #{ Time . now . year } Your Name" )
290-
291- File . write ( license_file , content )
292- end
293-
294303 def show_created_files
295304 Dir . glob ( "#{ @gem_name } /**/*" , File ::FNM_DOTMATCH ) . sort . each do |file |
296305 next if File . directory? ( file )
0 commit comments