bones 2.0.3 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/History.txt +11 -0
  2. data/Manifest.txt +20 -25
  3. data/README.txt +114 -83
  4. data/Rakefile +7 -6
  5. data/data/Rakefile.erb +7 -1
  6. data/data/bin/NAME.erb +1 -1
  7. data/data/lib/NAME.rb.erb +4 -11
  8. data/data/spec/NAME_spec.rb.erb +0 -1
  9. data/data/spec/spec_helper.rb.erb +0 -1
  10. data/lib/bones.rb +21 -8
  11. data/lib/bones/annotation_extractor.rb +1 -2
  12. data/lib/bones/debug.rb +0 -1
  13. data/lib/bones/main.rb +183 -109
  14. data/lib/bones/smtp_tls.rb +0 -1
  15. data/{data → lib/bones}/tasks/ann.rake +0 -1
  16. data/{data → lib/bones}/tasks/bones.rake +0 -1
  17. data/lib/bones/tasks/gem.rake +192 -0
  18. data/{data → lib/bones}/tasks/git.rake +0 -1
  19. data/{data → lib/bones}/tasks/manifest.rake +3 -4
  20. data/{data → lib/bones}/tasks/notes.rake +0 -1
  21. data/{data → lib/bones}/tasks/post_load.rake +2 -2
  22. data/{data → lib/bones}/tasks/rdoc.rake +0 -1
  23. data/{data → lib/bones}/tasks/rubyforge.rake +2 -4
  24. data/{data → lib/bones}/tasks/setup.rb +14 -3
  25. data/{data → lib/bones}/tasks/spec.rake +1 -2
  26. data/{data → lib/bones}/tasks/svn.rake +0 -1
  27. data/{data → lib/bones}/tasks/test.rake +3 -1
  28. data/spec/bones/main_spec.rb +157 -0
  29. data/spec/bones_spec.rb +18 -0
  30. data/spec/data/data/README.txt +0 -0
  31. data/spec/data/data/Rakefile +0 -0
  32. data/spec/data/foo/README.txt +0 -0
  33. data/spec/data/foo/Rakefile +0 -0
  34. data/spec/spec_helper.rb +22 -0
  35. data/tasks/ann.rake +0 -1
  36. data/tasks/bones.rake +0 -1
  37. data/tasks/gem.rake +98 -32
  38. data/tasks/git.rake +0 -1
  39. data/tasks/manifest.rake +3 -4
  40. data/tasks/notes.rake +0 -1
  41. data/tasks/post_load.rake +2 -2
  42. data/tasks/rdoc.rake +0 -1
  43. data/tasks/rubyforge.rake +2 -4
  44. data/tasks/setup.rb +14 -3
  45. data/tasks/spec.rake +1 -2
  46. data/tasks/svn.rake +47 -0
  47. data/tasks/test.rake +3 -1
  48. metadata +40 -17
  49. data/data/tasks/gem.rake +0 -126
@@ -1,4 +1,3 @@
1
- # $Id$
2
1
 
3
2
  require File.join(File.dirname(__FILE__), %w[spec_helper])
4
3
 
@@ -1,4 +1,3 @@
1
- # $Id$
2
1
 
3
2
  require File.expand_path(
4
3
  File.join(File.dirname(__FILE__), %w[.. lib <%= name %>]))
@@ -1,9 +1,8 @@
1
- # $Id$
2
1
 
3
2
  module Bones
4
3
 
5
4
  # :stopdoc:
6
- VERSION = '2.0.3'
5
+ VERSION = '2.1.0'
7
6
  PATH = File.expand_path(File.join(File.dirname(__FILE__), '..'))
8
7
  WIN32 = %r/win32/ =~ RUBY_PLATFORM
9
8
  DEV_NULL = WIN32 ? 'NUL:' : '/dev/null'
@@ -14,7 +13,7 @@ module Bones
14
13
  # <tt>File.join</tt>.
15
14
  #
16
15
  def self.path( *args )
17
- args.empty? ? PATH : File.join(PATH, *args)
16
+ args.empty? ? PATH : File.join(PATH, args.flatten)
18
17
  end
19
18
 
20
19
  # call-seq:
@@ -28,20 +27,34 @@ module Bones
28
27
  def self.require_all_libs_relative_to( fname, dir = nil )
29
28
  dir ||= File.basename(fname, '.*')
30
29
  search_me = File.expand_path(
31
- File.join(File.dirname(fname), dir, '**', '*.rb'))
30
+ File.join(File.dirname(fname), dir, '*.rb'))
32
31
 
33
32
  Dir.glob(search_me).sort.each {|rb| require rb}
34
33
  end
35
34
 
35
+ #
36
+ #
37
+ def self.setup
38
+ local_setup = File.join(Dir.pwd, %w[tasks setup.rb])
39
+
40
+ if test(?e, local_setup)
41
+ load local_setup
42
+ return
43
+ end
44
+
45
+ bones_setup = ::Bones.path %w[lib bones tasks setup.rb]
46
+ load bones_setup
47
+
48
+ rakefiles = Dir.glob(File.join(Dir.pwd, %w[tasks *.rake])).sort
49
+ import(*rakefiles)
50
+ end
51
+
36
52
  # TODO: fix file lists for Test::Unit and RSpec
37
53
  # these guys are just grabbing whatever is there and not pulling
38
54
  # the filenames from the manifest
39
55
 
40
- # TODO: create some tasks to generate e-mails / announcements
41
-
42
56
  end # module Bones
43
57
 
44
-
45
- Bones.require_all_libs_relative_to __FILE__
58
+ Bones.require_all_libs_relative_to(__FILE__)
46
59
 
47
60
  # EOF
@@ -1,4 +1,3 @@
1
- # $Id$
2
1
 
3
2
  begin
4
3
  require 'facets/ansicode'
@@ -85,7 +84,7 @@ class AnnotationExtractor
85
84
 
86
85
  text = m[2]
87
86
  if text =~ @id_rgxp
88
- text.gsub!(@id_rgxp) {|str| Console::ANSICode.green(str)} if HAVE_COLOR
87
+ text.gsub!(@id_rgxp) {|str| ANSICode.green(str)} if HAVE_COLOR
89
88
  list << Annotation.new(lineno, m[1], text)
90
89
  end
91
90
  list
@@ -1,4 +1,3 @@
1
- # $Id$
2
1
 
3
2
  require 'pp'
4
3
  require 'stringio'
@@ -1,4 +1,3 @@
1
- # $Id$
2
1
 
3
2
  require 'fileutils'
4
3
  require 'optparse'
@@ -7,102 +6,161 @@ require 'erb'
7
6
  module Bones
8
7
  class Main
9
8
 
10
- attr_writer :update
11
- attr_accessor :name, :data, :verbose, :output_dir
9
+ attr_reader :options
12
10
 
13
11
  # Create a new instance of Main, and run the +bones+ application given
14
12
  # the command line _args_.
15
13
  #
16
14
  def self.run( args )
17
15
  bones = self.new
18
- bones.parse args
16
+ bones.parse(args)
17
+ bones.run
18
+ end
19
+
20
+ # Create a new main instance using _io_ for standard output and _err_ for
21
+ # error messages.
22
+ #
23
+ def initialize( io = STDOUT, err = STDERR )
24
+ @io = io
25
+ @err = err
26
+ @options = {
27
+ :skeleton_dir => File.join(mrbones_dir, 'data'),
28
+ :with_tasks => false,
29
+ :verbose => false,
30
+ :name => nil,
31
+ :output_dir => nil,
32
+ :action => nil
33
+ }
34
+ @options[:skeleton_dir] = ::Bones.path('data') unless test(?d, skeleton_dir)
35
+ end
36
+
37
+ # The output directory where files will be written.
38
+ #
39
+ def output_dir
40
+ options[:output_dir]
41
+ end
19
42
 
20
- if bones.update? then bones.update
21
- else bones.create end
43
+ # The directory where the project skeleton is located.
44
+ #
45
+ def skeleton_dir
46
+ options[:skeleton_dir]
47
+ end
48
+
49
+ # The project name from the command line.
50
+ #
51
+ def name
52
+ options[:name]
53
+ end
54
+
55
+ # Returns the project name but converted to be usable as a Ruby class
56
+ # name.
57
+ #
58
+ def classname
59
+ name.tr('-','_').split('_').map {|x| x.capitalize}.join
60
+ end
61
+
62
+ # Returns +true+ if we are updating an already existing project. Returns
63
+ # +false+ if we are creating a new project.
64
+ #
65
+ def update?
66
+ test(?e, output_dir) and with_tasks?
67
+ end
68
+
69
+ # Returns +true+ if we are going to copy the Mr Bones tasks into the
70
+ # destination directory. Normally this will return +false+.
71
+ #
72
+ def with_tasks?
73
+ options[:with_tasks]
74
+ end
75
+
76
+ # Returns +true+ if the user has requested verbose messages.
77
+ #
78
+ def verbose?
79
+ options[:verbose]
22
80
  end
23
81
 
24
82
  # Parse the command line arguments and store the values for later use by
25
83
  # the +create+ and +update+ methods.
26
84
  #
27
85
  def parse( args )
28
- self.data = File.join(mrbones_dir, 'data')
29
- self.data = ::Bones.path('data') unless test(?d, data)
30
- self.update = false
31
- self.verbose = false
32
-
33
86
  opts = OptionParser.new
34
87
  opts.banner << ' project_name'
35
88
 
36
89
  opts.separator ''
37
- opts.on('-u', '--update',
38
- 'update the rake tasks for the project') {self.update = true}
39
- opts.on('-v', '--verbose',
40
- 'enable verbose output') {self.verbose = true}
90
+ opts.on('-v', '--verbose', 'enable verbose output') {
91
+ options[:verbose] = true
92
+ }
41
93
  opts.on('-d', '--directory DIRECTORY', String,
42
- 'project directory to create',
43
- '(defaults to project_name)') {|dir| self.output_dir = dir}
94
+ 'project directory to create', '(defaults to project_name)') {|dir|
95
+ options[:output_dir] = dir
96
+ }
44
97
  opts.on('-s', '--skeleton NAME', String,
45
- 'project skeleton to use') do |name|
46
- path = File.join(mrbones_dir, name)
98
+ 'project skeleton to use') do |skeleton_name|
99
+ path = File.join(mrbones_dir, skeleton_name)
47
100
  if test(?d, path)
48
- self.data = path
49
- elsif test(?d, name)
50
- self.data = name
101
+ options[:skeleton_dir] = path
102
+ elsif test(?d, skeleton_name)
103
+ options[:skeleton_dir] = skeleton_name
51
104
  else
52
- STDOUT.puts " unknown skeleton '#{name}'"
105
+ @io.puts " unknown skeleton '#{skeleton_name}'"
53
106
  exit
54
107
  end
55
108
  end
109
+ opts.on('--with-tasks', 'copy rake tasks to the project folder') {
110
+ options[:with_tasks] = true
111
+ }
56
112
 
57
113
  opts.separator ''
58
- opts.on('--freeze', 'freeze the project skeleton') {freeze; exit}
59
- opts.on('--unfreeze', 'use the standard project skeleton') {unfreeze; exit}
60
- opts.on('-i', '--info',
61
- 'report on the project skeleton being used') do
62
- STDOUT.puts "the project skeleton will be copied from"
63
- STDOUT.write " "
64
- STDOUT.puts data
65
- exit
66
- end
114
+ opts.on('--freeze', 'freeze the project skeleton') {
115
+ options[:action] = :freeze
116
+ }
117
+ opts.on('--unfreeze', 'use the standard project skeleton') {
118
+ options[:action] = :unfreeze
119
+ }
120
+ opts.on('-i', '--info', 'report on the project skeleton being used') {
121
+ options[:action] = :info
122
+ }
67
123
 
68
124
  opts.separator ''
69
125
  opts.separator 'common options:'
70
-
71
- opts.on_tail( '-h', '--help', 'show this message' ) do
72
- STDOUT.puts opts
126
+ opts.on_tail( '-h', '--help', 'show this message' ) {
127
+ @io.puts opts
73
128
  exit
74
- end
75
-
76
- opts.on_tail( '--version', 'show version' ) do
77
- STDOUT.puts "Mr Bones #{::Bones::VERSION}"
129
+ }
130
+ opts.on_tail( '--version', 'show version' ) {
131
+ @io.puts "Mr Bones #{::Bones::VERSION}"
78
132
  exit
79
- end
133
+ }
80
134
 
81
135
  # parse the command line arguments
82
136
  opts.parse! args
83
- self.name = args.empty? ? nil : args.join('_')
137
+ options[:name] = args.empty? ? nil : args.join('_')
84
138
 
85
- if name.nil?
86
- STDOUT.puts opts
139
+ if options[:action].nil? and name.nil?
140
+ @io.puts opts
87
141
  ::Kernel.abort
88
142
  end
89
143
 
90
- self.output_dir = name if output_dir.nil?
144
+ options[:output_dir] = name if output_dir.nil?
91
145
  nil
92
146
  end
93
147
 
94
- # Returns +true+ if we are updating an already existing project. Returns
95
- # +false+ if we are creating a new project.
96
- #
97
- def update?
98
- @update
99
- end
100
-
101
- # Returns the project name but converted to be usable as a Ruby class
102
- # name.
148
+ # Run the main application.
103
149
  #
104
- def classname
105
- name.tr('-','_').split('_').map {|x| x.capitalize}.join
150
+ def run
151
+ case options[:action]
152
+ when :freeze
153
+ freeze
154
+ when :unfreeze
155
+ unfreeze
156
+ when :info
157
+ @io.puts "the project skeleton will be copied from"
158
+ @io.write " "
159
+ @io.puts skeleton_dir
160
+ else
161
+ if update? then update
162
+ else create end
163
+ end
106
164
  end
107
165
 
108
166
  # Create a new project from the bones/data project template.
@@ -113,17 +171,18 @@ class Main
113
171
 
114
172
  begin
115
173
  files_to_copy.each {|fn| cp fn}
174
+ copy_tasks(File.join(output_dir, 'tasks')) if with_tasks?
116
175
 
117
176
  pwd = File.expand_path(FileUtils.pwd)
118
177
  msg = "created '#{name}'"
119
178
  msg << " in directory '#{output_dir}'" if name != output_dir
120
- STDOUT.puts msg
179
+ @io.puts msg
121
180
 
122
181
  if test(?f, File.join(output_dir, 'Rakefile'))
123
182
  begin
124
183
  FileUtils.cd output_dir
125
184
  system "rake manifest:create 2>&1 > #{::Bones::DEV_NULL}"
126
- STDOUT.puts "now you need to fix these files"
185
+ @io.puts "now you need to fix these files"
127
186
  system "rake notes"
128
187
  ensure
129
188
  FileUtils.cd pwd
@@ -144,7 +203,7 @@ class Main
144
203
  abort "'#{output_dir}' does not exist" unless test ?e, output_dir
145
204
 
146
205
  task_dir = File.join(output_dir, 'tasks')
147
- abort "no tasks directory found in '#{output_dir}'" unless test ?d, task_dir
206
+ FileUtils.mkdir_p(task_dir) unless test(?d, task_dir)
148
207
 
149
208
  archive_dir = File.join(task_dir, 'archive')
150
209
  FileUtils.rm_rf archive_dir
@@ -155,14 +214,11 @@ class Main
155
214
  FileUtils.cp fn, archive_dir
156
215
  end
157
216
 
158
- files_to_copy.each do |fn|
159
- next unless %r/^tasks\// =~ fn
160
- cp fn
161
- end
217
+ copy_tasks(task_dir)
162
218
 
163
219
  msg = "updated tasks for '#{name}'"
164
220
  msg << " in directory '#{output_dir}'" if name != output_dir
165
- STDOUT.puts msg
221
+ @io.puts msg
166
222
  end
167
223
 
168
224
  # Freeze the project skeleton to the current Mr Bones gem. If the project
@@ -173,41 +229,28 @@ class Main
173
229
  # Bones skeleton will be copied to the user's data directory.
174
230
  #
175
231
  def freeze
176
- self.data = ::Bones.path('data')
177
- data_dir = File.join(mrbones_dir, 'data')
178
- archive_dir = File.join(mrbones_dir, 'archive')
179
- tasks_only = false
180
-
181
- if test(?d, data_dir)
182
- STDOUT.puts "archiving #{data_dir}" if verbose
183
- FileUtils.rm_rf(archive_dir)
184
- FileUtils.mkdir(archive_dir)
185
- FileUtils.cp_r(File.join(data_dir, '.'), archive_dir)
186
- tasks_only = true
187
- else
188
- FileUtils.mkdir_p(data_dir)
189
- end
232
+ options[:skeleton_dir] = ::Bones.path('data')
233
+ options[:name] = 'data' if name.nil?
234
+ options[:output_dir] = File.join(mrbones_dir, name)
190
235
 
191
- files_to_copy.each do |file|
192
- next if tasks_only && !(%r/^tasks\// =~ file)
236
+ archive(output_dir, "#{output_dir}.archive")
237
+ FileUtils.mkdir_p(output_dir)
193
238
 
194
- src = File.join(data, file)
195
- dst = File.join(data_dir, file)
239
+ files_to_copy.each do |file|
240
+ src = File.join(skeleton_dir, file)
241
+ dst = File.join(output_dir, file)
196
242
 
197
- STDOUT.puts "freezing #{dst}" if verbose
243
+ @io.puts "freezing #{dst}" if verbose?
198
244
  FileUtils.mkdir_p(File.dirname(dst))
199
245
  FileUtils.cp(src, dst)
200
246
  end
201
247
 
248
+ copy_tasks(File.join(output_dir, 'tasks'), 'freezing') if with_tasks?
249
+
202
250
  File.open(frozen_version_file, 'w') {|fd| fd.puts ::Bones::VERSION}
203
251
 
204
- if tasks_only
205
- STDOUT.puts "project skeleton tasks have been updated " <<
206
- "from Mr Bones #{::Bones::VERSION}"
207
- else
208
- STDOUT.puts "project skeleton has been frozen " <<
252
+ @io.puts "project skeleton has been frozen " <<
209
253
  "to Mr Bones #{::Bones::VERSION}"
210
- end
211
254
  end
212
255
 
213
256
  # Unfreeze the project skeleton. The default Mr Bones skeleton will be
@@ -215,20 +258,14 @@ class Main
215
258
  # one exists.
216
259
  #
217
260
  def unfreeze
218
- data_dir = File.join(mrbones_dir, 'data')
219
- archive_dir = File.join(mrbones_dir, 'archive')
220
-
221
- if test(?d, data_dir)
222
- STDOUT.puts "archiving #{data_dir}" if verbose
223
- FileUtils.rm_rf(archive_dir)
224
- FileUtils.mkdir(archive_dir)
225
- FileUtils.cp_r(File.join(data_dir, '.'), archive_dir)
226
- FileUtils.rm_rf(data_dir)
227
-
228
- STDOUT.puts "project skeleton has been unfrozen"
229
- STDOUT.puts "(default Mr Bones #{::Bones::VERSION} sekeleton will be used)"
261
+ options[:name] = 'data' if name.nil?
262
+ options[:output_dir] = File.join(mrbones_dir, name)
263
+
264
+ if archive(output_dir, "#{output_dir}.archive")
265
+ @io.puts "project skeleton has been unfrozen"
266
+ @io.puts "(default Mr Bones #{::Bones::VERSION} skeleton will be used)"
230
267
  else
231
- STDOUT.puts "project skeleton is not frozen (no action taken)"
268
+ @io.puts "project skeleton is not frozen (no action taken)"
232
269
  end
233
270
  FileUtils.rm_f frozen_version_file
234
271
  end
@@ -237,10 +274,10 @@ class Main
237
274
  # the new project directory
238
275
  #
239
276
  def files_to_copy
240
- rgxp = %r/\A#{data}\/?/o
277
+ rgxp = %r/\A#{skeleton_dir}\/?/o
241
278
  exclude = %r/tmp$|bak$|~$|CVS|\.svn/o
242
279
 
243
- ary = Dir.glob(File.join(data, '**', '*')).map do |filename|
280
+ ary = Dir.glob(File.join(skeleton_dir, '**', '*')).map do |filename|
244
281
  next if exclude =~ filename
245
282
  next if test(?d, filename)
246
283
  filename.sub rgxp, ''
@@ -251,9 +288,6 @@ class Main
251
288
  ary
252
289
  end
253
290
 
254
-
255
- private
256
-
257
291
  # Copy a file from the Bones prototype project location to the user
258
292
  # specified project location. A message will be displayed to the screen
259
293
  # indicating that the file is being created.
@@ -262,9 +296,9 @@ class Main
262
296
  dir = File.dirname(file).sub('NAME', name)
263
297
  dir = (dir == '.' ? output_dir : File.join(output_dir, dir))
264
298
  dst = File.join(dir, File.basename(file, '.erb').sub('NAME', name))
265
- src = File.join(data, file)
299
+ src = File.join(skeleton_dir, file)
266
300
 
267
- STDOUT.puts(test(?e, dst) ? "updating #{dst}" : "creating #{dst}") if verbose
301
+ @io.puts(test(?e, dst) ? "updating #{dst}" : "creating #{dst}") if verbose?
268
302
  FileUtils.mkdir_p(dir)
269
303
 
270
304
  if '.erb' == File.extname(file)
@@ -277,10 +311,50 @@ class Main
277
311
  FileUtils.chmod(File.stat(src).mode, dst)
278
312
  end
279
313
 
314
+ # Archive the contents of the _from_ directory into the _to_ directory.
315
+ # The _to_ directory will be deleted if it currently exists. After the
316
+ # copy the _from_ directory will be deleted.
317
+ #
318
+ # Returns +true+ if the directory was archived. Returns +false+ if the
319
+ # directory was not archived.
320
+ #
321
+ def archive( from, to )
322
+ if test(?d, from)
323
+ @io.puts "archiving #{from}" if verbose?
324
+ FileUtils.rm_rf(to)
325
+ FileUtils.mkdir(to)
326
+ FileUtils.cp_r(File.join(from, '.'), to)
327
+ FileUtils.rm_rf(from)
328
+ true
329
+ else
330
+ false
331
+ end
332
+ end
333
+
334
+ # Copy the Mr Bones tasks into the _to_ directory. If we are in verbose
335
+ # mode, then a message will be displayed to the user. This message can be
336
+ # passed in as the _msg_ argument. The current file being copied is
337
+ # appened to the end of the message.
338
+ #
339
+ def copy_tasks( to, msg = nil )
340
+ Dir.glob(::Bones.path(%w[lib bones tasks *])).sort.each do |src|
341
+ dst = File.join(to, File.basename(src))
342
+
343
+ if msg
344
+ @io.puts "#{msg} #{dst}" if verbose?
345
+ else
346
+ @io.puts(test(?e, dst) ? "updating #{dst}" : "creating #{dst}") if verbose?
347
+ end
348
+
349
+ FileUtils.mkdir_p(File.dirname(dst))
350
+ FileUtils.cp(src, dst)
351
+ end
352
+ end
353
+
280
354
  # Prints an abort _msg_ to the screen and then exits the Ruby interpreter.
281
355
  #
282
356
  def abort( msg )
283
- STDERR.puts msg
357
+ @err.puts msg
284
358
  exit 1
285
359
  end
286
360