bones 2.5.1 → 3.0.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 (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