bones 2.5.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/History.txt +2 -0
  2. data/README.rdoc +54 -306
  3. data/Rakefile +28 -37
  4. data/bin/bones +10 -3
  5. data/{spec/data/data → default}/.bnsignore +3 -1
  6. data/{data → default}/History.txt.bns +0 -0
  7. data/{data → default}/README.txt.bns +0 -0
  8. data/default/Rakefile.bns +21 -0
  9. data/{data → default}/bin/NAME.bns +0 -0
  10. data/{data → default}/lib/NAME.rb.bns +0 -0
  11. data/{data → default}/spec/NAME_spec.rb.bns +0 -0
  12. data/{data → default}/spec/spec_helper.rb.bns +0 -0
  13. data/{data → default}/test/test_NAME.rb +0 -0
  14. data/lib/bones.rb +73 -31
  15. data/lib/bones/annotation_extractor.rb +16 -26
  16. data/lib/bones/app.rb +87 -58
  17. data/lib/bones/app/command.rb +143 -64
  18. data/lib/bones/app/create.rb +93 -0
  19. data/lib/bones/app/file_manager.rb +7 -8
  20. data/lib/bones/app/freeze.rb +59 -0
  21. data/lib/bones/app/info.rb +39 -0
  22. data/lib/bones/app/unfreeze.rb +44 -0
  23. data/lib/bones/colors.rb +54 -0
  24. data/lib/bones/gem_package_task.rb +71 -0
  25. data/lib/bones/helpers.rb +93 -0
  26. data/lib/bones/plugins/ann.rb +166 -0
  27. data/lib/bones/plugins/bones_plugin.rb +193 -0
  28. data/lib/bones/plugins/gem.rb +274 -0
  29. data/lib/bones/plugins/notes.rb +45 -0
  30. data/lib/bones/plugins/rdoc.rb +93 -0
  31. data/lib/bones/plugins/test.rb +57 -0
  32. data/lib/bones/smtp_tls.rb +1 -0
  33. data/spec/bones/app/file_manager_spec.rb +6 -6
  34. data/spec/bones/app_spec.rb +14 -18
  35. data/spec/bones_spec.rb +9 -4
  36. data/{data → spec/data/default}/.bnsignore +0 -0
  37. data/spec/data/{data → default}/History +0 -0
  38. data/spec/data/{data → default}/NAME/NAME.rb.bns +0 -0
  39. data/spec/data/{data → default}/README.txt.bns +0 -0
  40. data/{data → spec/data/default}/Rakefile.bns +0 -0
  41. data/spec/data/{data → default}/lib/NAME.rb.bns +0 -0
  42. metadata +94 -68
  43. data/lib/bones/app/create_command.rb +0 -86
  44. data/lib/bones/app/freeze_command.rb +0 -73
  45. data/lib/bones/app/info_command.rb +0 -58
  46. data/lib/bones/app/unfreeze_command.rb +0 -53
  47. data/lib/bones/app/update_command.rb +0 -47
  48. data/lib/bones/debug.rb +0 -72
  49. data/lib/bones/tasks/ann.rake +0 -80
  50. data/lib/bones/tasks/bones.rake +0 -20
  51. data/lib/bones/tasks/gem.rake +0 -201
  52. data/lib/bones/tasks/git.rake +0 -40
  53. data/lib/bones/tasks/notes.rake +0 -27
  54. data/lib/bones/tasks/post_load.rake +0 -34
  55. data/lib/bones/tasks/rdoc.rake +0 -51
  56. data/lib/bones/tasks/rubyforge.rake +0 -55
  57. data/lib/bones/tasks/setup.rb +0 -292
  58. data/lib/bones/tasks/spec.rake +0 -54
  59. data/lib/bones/tasks/svn.rake +0 -47
  60. data/lib/bones/tasks/test.rake +0 -40
  61. data/lib/bones/tasks/zentest.rake +0 -36
  62. data/spec/data/data/Rakefile.bns +0 -30
  63. data/tasks/ann.rake +0 -80
  64. data/tasks/bones.rake +0 -20
  65. data/tasks/gem.rake +0 -201
  66. data/tasks/git.rake +0 -40
  67. data/tasks/notes.rake +0 -27
  68. data/tasks/post_load.rake +0 -34
  69. data/tasks/rdoc.rake +0 -51
  70. data/tasks/rubyforge.rake +0 -55
  71. data/tasks/setup.rb +0 -292
  72. data/tasks/spec.rake +0 -54
  73. data/tasks/svn.rake +0 -47
  74. data/tasks/test.rake +0 -40
  75. data/tasks/zentest.rake +0 -36
@@ -0,0 +1,39 @@
1
+
2
+ module Bones::App
3
+ class Info < Command
4
+
5
+ def self.initialize_info
6
+ synopsis 'bones info'
7
+ summary 'show information about available skeletons'
8
+ description 'Shows information about available skeletons.'
9
+ end
10
+
11
+ def run
12
+ skeleton_dir = File.join(mrbones_dir, DEFAULT_SKELETON)
13
+ skeleton_dir = ::Bones.path(DEFAULT_SKELETON) unless test(?d, skeleton_dir)
14
+
15
+ msg = "\n"
16
+ msg << "The default project skeleton will be copied from:\n"
17
+ msg << " " << skeleton_dir << "\n\n"
18
+
19
+ fmt = " %-12s => %s\n"
20
+ msg << "Available projects skeletons are:\n"
21
+ Dir.glob(File.join(mrbones_dir, '*')).sort.each do |fn|
22
+ next if fn =~ %r/\.archive$/
23
+ next if File.basename(fn) == DEFAULT_SKELETON
24
+
25
+ if test(?f, fn)
26
+ msg << fmt % [File.basename(fn), File.read(fn).strip]
27
+ else
28
+ msg << " " << File.basename(fn) << "\n"
29
+ end
30
+ end
31
+
32
+ stdout.puts msg
33
+ stdout.puts
34
+ end
35
+
36
+ end # class Info
37
+ end # module Bones::App
38
+
39
+ # EOF
@@ -0,0 +1,44 @@
1
+
2
+ module Bones::App
3
+ class Unfreeze < Command
4
+
5
+ def self.initialize_unfreeze
6
+ synopsis 'bones unfreeze [skeleton_name]'
7
+
8
+ summary 'remove a skeleton from ~/.mrbones/'
9
+
10
+ description <<-__
11
+ Removes the named skeleton from the '~/.mrbones/' folder. If a name is
12
+ not given then the default skeleton is removed.
13
+ __
14
+
15
+ option(standard_options[:verbose])
16
+ end
17
+
18
+ def run
19
+ fm = FileManager.new(
20
+ :source => repository || ::Bones.path(DEFAULT_SKELETON),
21
+ :destination => output_dir,
22
+ :stdout => stdout,
23
+ :stderr => stderr,
24
+ :verbose => verbose?
25
+ )
26
+
27
+ if fm.archive_destination
28
+ stdout.puts "Project skeleton #{name.inspect} has been unfrozen"
29
+ else
30
+ stdout.puts "Project skeleton #{name.inspect} is not frozen " <<
31
+ "(no action taken)"
32
+ end
33
+ end
34
+
35
+ def parse( args )
36
+ opts = super args
37
+ config[:name] = args.empty? ? DEFAULT_SKELETON : args.join('_')
38
+ config[:output_dir] = File.join(mrbones_dir, name)
39
+ end
40
+
41
+ end # class Unfreeze
42
+ end # module Bones::App
43
+
44
+ # EOF
@@ -0,0 +1,54 @@
1
+
2
+ module Bones::Colors
3
+ extend self
4
+
5
+ COLOR_CODES = {
6
+ :clear => 0,
7
+ :reset => 0, # synonym for :clear
8
+ :bold => 1,
9
+ :dark => 2,
10
+ :italic => 3, # not widely implemented
11
+ :underline => 4,
12
+ :underscore => 4, # synonym for :underline
13
+ :blink => 5,
14
+ :rapid_blink => 6, # not widely implemented
15
+ :negative => 7, # no reverse because of String#reverse
16
+ :concealed => 8,
17
+ :strikethrough => 9, # not widely implemented
18
+ :black => 30,
19
+ :red => 31,
20
+ :green => 32,
21
+ :yellow => 33,
22
+ :blue => 34,
23
+ :magenta => 35,
24
+ :cyan => 36,
25
+ :white => 37,
26
+ :on_black => 40,
27
+ :on_red => 41,
28
+ :on_green => 42,
29
+ :on_yellow => 43,
30
+ :on_blue => 44,
31
+ :on_magenta => 45,
32
+ :on_cyan => 46,
33
+ :on_white => 47
34
+ }
35
+
36
+ COLOR_CODES.each { |name,code|
37
+ module_eval <<-CODE
38
+ def #{name.to_s}( str )
39
+ "\e[#{code}m\#{str}\e[0m"
40
+ end
41
+ CODE
42
+ }
43
+
44
+ def colorize( str, *args )
45
+ args.each { |name|
46
+ code = COLOR_CODES[name]
47
+ next if code.nil?
48
+ str = "\e[#{code}m#{str}\e[0m"
49
+ }
50
+ str
51
+ end
52
+ end # module Bones::Colors
53
+
54
+ # EOF
@@ -0,0 +1,71 @@
1
+
2
+ require 'find'
3
+ require 'rake/packagetask'
4
+ require 'rubygems/user_interaction'
5
+ require 'rubygems/builder'
6
+
7
+ class Bones::GemPackageTask < Rake::PackageTask
8
+
9
+ # Ruby GEM spec containing the metadata for this package. The
10
+ # name, version and package_files are automatically determined
11
+ # from the GEM spec and don't need to be explicitly provided.
12
+ #
13
+ attr_accessor :gem_spec
14
+
15
+ # Create a GEM Package task library. Automatically define the gem
16
+ # if a block is given. If no block is supplied, then +define+
17
+ # needs to be called to define the task.
18
+ #
19
+ def initialize(gem_spec)
20
+ init(gem_spec)
21
+ yield self if block_given?
22
+ define if block_given?
23
+ end
24
+
25
+ # Initialization tasks without the "yield self" or define
26
+ # operations.
27
+ #
28
+ def init(gem)
29
+ super(gem.name, gem.version)
30
+ @gem_spec = gem
31
+ @package_files += gem_spec.files if gem_spec.files
32
+ end
33
+
34
+ # Create the Rake tasks and actions specified by this
35
+ # GemPackageTask. (+define+ is automatically called if a block is
36
+ # given to +new+).
37
+ #
38
+ def define
39
+ super
40
+ task :prereqs
41
+ task :package => ['gem:prereqs', "#{package_dir_path}/#{gem_file}"]
42
+
43
+ file "#{package_dir_path}/#{gem_file}" => [package_dir_path] + package_files do
44
+ when_writing("Creating GEM") {
45
+ chdir(package_dir_path) do
46
+ Gem::Builder.new(gem_spec).build
47
+ verbose(true) {
48
+ mv gem_file, "../#{gem_file}"
49
+ }
50
+ end
51
+ }
52
+ end
53
+
54
+ file package_dir_path do
55
+ mkdir_p package_dir rescue nil
56
+ end
57
+ end
58
+
59
+ #
60
+ #
61
+ def gem_file
62
+ if @gem_spec.platform == Gem::Platform::RUBY
63
+ "#{package_name}.gem"
64
+ else
65
+ "#{package_name}-#{@gem_spec.platform}.gem"
66
+ end
67
+ end
68
+
69
+ end # class Bones::GemPackageTask
70
+
71
+ # EOF
@@ -0,0 +1,93 @@
1
+
2
+ module Bones::Helpers
3
+
4
+ DEV_NULL = File.exist?('/dev/null') ? '/dev/null' : 'NUL:'
5
+ SUDO = if system("which sudo > #{DEV_NULL} 2>&1") then 'sudo'
6
+ else '' end unless defined? SUDO
7
+ RCOV = "#{RUBY} -S rcov"
8
+ RDOC = "#{RUBY} -S rdoc"
9
+ GEM = "#{RUBY} -S gem"
10
+ HAVE_SVN = (Dir.entries(Dir.pwd).include?('.svn') and
11
+ system("svn --version 2>&1 > #{DEV_NULL}"))
12
+
13
+ HAVE = Hash.new(false)
14
+
15
+ def have?( key, &block )
16
+ return HAVE[key] if block.nil?
17
+ HAVE[key] = block.call
18
+ end
19
+
20
+ def quiet( &block )
21
+ io = [STDOUT.dup, STDERR.dup]
22
+ STDOUT.reopen DEV_NULL
23
+ STDERR.reopen DEV_NULL
24
+ block.call
25
+ ensure
26
+ STDOUT.reopen io.first
27
+ STDERR.reopen io.last
28
+ io.each {|x| x.close}
29
+ end
30
+
31
+ # Reads a file at +path+ and spits out an array of the +paragraphs+
32
+ # specified.
33
+ #
34
+ # changes = paragraphs_of('History.txt', 0..1).join("\n\n")
35
+ # summary, *description = paragraphs_of('README.txt', 3, 3..8)
36
+ #
37
+ def paragraphs_of( path, *paragraphs )
38
+ title = String === paragraphs.first ? paragraphs.shift : nil
39
+ ary = File.read(path).delete("\r").split(/\n\n+/)
40
+
41
+ result = if title
42
+ tmp, matching = [], false
43
+ rgxp = %r/^=+\s*#{Regexp.escape(title)}/i
44
+ paragraphs << (0..-1) if paragraphs.empty?
45
+
46
+ ary.each do |val|
47
+ if val =~ rgxp
48
+ break if matching
49
+ matching = true
50
+ rgxp = %r/^=+/i
51
+ elsif matching
52
+ tmp << val
53
+ end
54
+ end
55
+ tmp
56
+ else ary end
57
+
58
+ result.values_at(*paragraphs)
59
+ end
60
+
61
+ # Find a rake task using the task name and remove any description text. This
62
+ # will prevent the task from being displayed in the list of available tasks.
63
+ #
64
+ def remove_desc_for_task( names )
65
+ Array(names).each do |task_name|
66
+ task = Rake.application.tasks.find {|t| t.name == task_name}
67
+ next if task.nil?
68
+ task.instance_variable_set :@comment, nil
69
+ end
70
+ end
71
+
72
+ end # module Bones::Helpers
73
+
74
+ # We need a "valid" method thtat determines if a string is suitable for use
75
+ # in the gem specification.
76
+ #
77
+ class Object
78
+ def valid?
79
+ return !(self.empty? or self == "\000") if self.respond_to?(:to_str)
80
+ return false
81
+ end
82
+
83
+ # Adds the given arguments to the include path if they are not already there
84
+ #
85
+ def ensure_in_path( *args )
86
+ args.each do |path|
87
+ path = File.expand_path(path)
88
+ $:.unshift(path) if test(?d, path) and not $:.include?(path)
89
+ end
90
+ end
91
+ end
92
+
93
+ # EOF
@@ -0,0 +1,166 @@
1
+
2
+ module Bones::Plugins::Ann
3
+ include ::Bones::Helpers
4
+ extend self
5
+
6
+ module Syntax
7
+ def use_gmail( user = nil )
8
+ email = ::Bones.config.ann.email
9
+ user ||= ::Bones.config.email
10
+
11
+ email.username user
12
+ email.server 'smtp.gmail.com'
13
+ email.port 587
14
+ email.authtype :plain
15
+ end
16
+ end
17
+
18
+ def initialize_ann
19
+ ::Bones.config {
20
+ desc 'Configuration for creating and mailing an announcement message.'
21
+ ann {
22
+ file 'announcement.txt', :desc => <<-__
23
+ When announcing a release of your project the announcement text will
24
+ be written to this file.
25
+ __
26
+
27
+ text nil, :desc => 'Extra text to be appended to the announcement.'
28
+
29
+ paragraphs Array.new, :desc => <<-__
30
+ Array of paragraphs from the README file to include in the
31
+ announcement. The paragraphs are identified by their heading name in
32
+ the README, but when listed here they can be given as lowercase or
33
+ uppercase.
34
+ __
35
+
36
+ desc <<-__
37
+ Configuration for e-mailing the announcement.
38
+
39
+ A convenience method is provided for configuring Mr Bones to use
40
+ gmail for sending project announcements. The project's e-mail
41
+ address isused by default if a gmail username is not supplied.
42
+ |
43
+ | use_gmail
44
+ | use_gmail 'username'
45
+ |
46
+ Use the latter form of the method is your gmail username is
47
+ different then the project's e-mail address.
48
+ __
49
+ email {
50
+ from nil, :desc => <<-__
51
+ The name to show on the 'from' line of the annoucement e-mail.
52
+ This will default to the author name or the project e-mail if an
53
+ author is not specified.
54
+ __
55
+
56
+ to %w(ruby-talk@ruby-lang.org), :desc => 'An array of e-mail recipients.'
57
+
58
+ server 'localhost', :desc => 'The server used to send the announcement e-mail.'
59
+
60
+ port 25, :desc => 'The server port number to connect to.'
61
+
62
+ domain ENV['HOSTNAME'], :desc => <<-__
63
+ The originating domain of the e-mail. This safely deafaults to the
64
+ local hostname.
65
+ __
66
+
67
+ username nil, :desc => 'The e-mail account name used to log into the e-mail server.'
68
+
69
+ password nil, :desc => 'The e-mail password used to log into the e-mail server.'
70
+
71
+ authtype :plain, :desc => <<-__
72
+ The authentication type used by the e-mail server. This should be
73
+ one of :plain, :login, or :cram_md5. See the documentation on the
74
+ Net::SMTP class for more information.
75
+ __
76
+ }
77
+ }
78
+ }
79
+
80
+ have?(:ann) { true }
81
+ end
82
+
83
+ def post_load
84
+ config = ::Bones.config
85
+
86
+ config.exclude << "^#{Regexp.escape(config.ann.file)}$"
87
+ config.ann.email.from ||= Array(config.authors).first || config.email
88
+ config.ann.email.username ||= config.email
89
+ config.ann.email.domain ||= 'localhost'
90
+ end
91
+
92
+ def define_tasks
93
+ config = ::Bones.config
94
+ namespace :ann do
95
+
96
+ # A prerequisites task that all other tasks depend upon
97
+ task :prereqs
98
+
99
+ file config.ann.file do
100
+ ann = config.ann
101
+ puts "Generating #{ann.file}"
102
+ File.open(ann.file,'w') do |fd|
103
+ fd.puts("#{config.name} version #{config.version}")
104
+ fd.puts(" by #{Array(config.authors).first}") if config.authors
105
+ fd.puts(" #{config.url}") if config.url.valid?
106
+ fd.puts(" (the \"#{config.release_name}\" release)") if config.release_name
107
+ fd.puts
108
+ fd.puts("== DESCRIPTION")
109
+ fd.puts
110
+ fd.puts(config.description)
111
+ fd.puts
112
+ fd.puts(config.changes.sub(%r/^.*$/, '== CHANGES'))
113
+ fd.puts
114
+ ann.paragraphs.each do |p|
115
+ fd.puts "== #{p.upcase}"
116
+ fd.puts
117
+ fd.puts paragraphs_of(config.readme_file, p).join("\n\n")
118
+ fd.puts
119
+ end
120
+ fd.puts ann.text if ann.text
121
+ end
122
+ end
123
+
124
+ desc "Create an announcement file"
125
+ task :announcement => ['ann:prereqs', config.ann.file]
126
+
127
+ desc "Send an email announcement"
128
+ task :email => ['ann:prereqs', config.ann.file] do
129
+ ann = config.ann
130
+ email = config.ann.email
131
+
132
+ from = email.from
133
+ to = Array(email.to)
134
+
135
+ ### build a mail header for RFC 822
136
+ rfc822msg = "From: #{from}\n"
137
+ rfc822msg << "To: #{to.join(',')}\n"
138
+ rfc822msg << "Subject: [ANN] #{config.name} #{config.version}"
139
+ rfc822msg << " (#{config.release_name})" if config.release_name
140
+ rfc822msg << "\n"
141
+ rfc822msg << "Date: #{Time.new.rfc822}\n"
142
+ rfc822msg << "Message-Id: "
143
+ rfc822msg << "<#{"%.8f" % Time.now.to_f}@#{email.domain}>\n\n"
144
+ rfc822msg << File.read(ann.file)
145
+
146
+ params = [:server, :port, :domain, :username, :password, :authtype].map { |key| email[key] }
147
+
148
+ if params[4].nil?
149
+ STDOUT.write "Please enter your e-mail password (#{params[3]}): "
150
+ params[4] = STDIN.gets.chomp
151
+ end
152
+
153
+ ### send email
154
+ Net::SMTP.start(*params) {|smtp| smtp.sendmail(rfc822msg, from, to)}
155
+ end
156
+ end # namespace :ann
157
+
158
+ desc 'Alias to ann:announcement'
159
+ task :ann => 'ann:announcement'
160
+
161
+ CLOBBER << config.ann.file
162
+ end
163
+
164
+ end # module Bones::Plugins::Ann
165
+
166
+ # EOF