bones 2.0.3 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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