blackwinter-hen 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/lib/hen.rb ADDED
@@ -0,0 +1,305 @@
1
+ #--
2
+ ###############################################################################
3
+ # #
4
+ # hen -- Just a Rake helper #
5
+ # #
6
+ # Copyright (C) 2007-2008 University of Cologne, #
7
+ # Albertus-Magnus-Platz, #
8
+ # 50932 Cologne, Germany #
9
+ # #
10
+ # Authors: #
11
+ # Jens Wille <jens.wille@uni-koeln.de> #
12
+ # #
13
+ # hen is free software; you can redistribute it and/or modify it under the #
14
+ # terms of the GNU General Public License as published by the Free Software #
15
+ # Foundation; either version 3 of the License, or (at your option) any later #
16
+ # version. #
17
+ # #
18
+ # hen is distributed in the hope that it will be useful, but WITHOUT ANY #
19
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS #
20
+ # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more #
21
+ # details. #
22
+ # #
23
+ # You should have received a copy of the GNU General Public License along #
24
+ # with hen. If not, see <http://www.gnu.org/licenses/>. #
25
+ # #
26
+ ###############################################################################
27
+ #++
28
+
29
+ require 'yaml'
30
+ require 'forwardable'
31
+
32
+ require 'rubygems'
33
+ require 'rake'
34
+ require 'nuggets/env/user_home'
35
+ require 'nuggets/proc/bind'
36
+
37
+ require 'hen/dsl'
38
+ require 'hen/version'
39
+
40
+ class Hen
41
+
42
+ # The directories which contain the hen files
43
+ HENDIRS = [File.join(File.dirname(__FILE__), 'hens')] +
44
+ (ENV['HENPATH'] || '').split(File::PATH_SEPARATOR)
45
+
46
+ # All hens found, mapped by their name
47
+ HENS = Dir[*HENDIRS.map { |d| "#{d}/*.rake" }].uniq.inject(
48
+ Hash.new { |h, k| h[k] = [] }
49
+ ) { |hash, hen|
50
+ hash[File.basename(hen, '.rake')] << hen; hash
51
+ }
52
+
53
+ # Directories to search for .henrc
54
+ RCDIRS = ['.', ENV.user_home]
55
+
56
+ # A container for all loaded hens
57
+ @hens = {}
58
+
59
+ # The verbosity concerning errors and warnings
60
+ @verbose = true
61
+
62
+ class << self
63
+
64
+ attr_reader :hens, :verbose
65
+
66
+ # call-seq:
67
+ # lay!
68
+ # lay!(:some_hen, :some_other_hen)
69
+ # lay!(:exclude => [:some_hen, :some_other_hen])
70
+ #
71
+ # Loads the hens, causing them to lay their eggs^H^H^Htasks. Either all,
72
+ # if no restrictions are specified, or the given hens, or all but those
73
+ # given in the <tt>:exclude</tt> option.
74
+ def lay!(*args)
75
+ # Extract potential options hash
76
+ options = args.last.is_a?(Hash) ? args.pop : {}
77
+
78
+ @verbose = options[:verbose] if options.has_key?(:verbose)
79
+
80
+ if block_given?
81
+ yield.each { |key, value|
82
+ config[key].update(value)
83
+ }
84
+ end
85
+
86
+ # Handle include/exclude requirements
87
+ excl = options[:exclude]
88
+ args, default = args.empty? ? [excl ? [*excl] : [], true] : [args, false]
89
+
90
+ inclexcl = Hash.new(default)
91
+ args.each { |arg|
92
+ inclexcl[arg.to_s] = !default
93
+ }
94
+
95
+ # Load all available hens (as far as the
96
+ # include/exclude conditions are met)
97
+ load_hens { |hen|
98
+ inclexcl[hen]
99
+ }
100
+
101
+ # Execute each hen definition
102
+ hens.each { |name, hen|
103
+ # Load any dependencies, in case they're not included yet
104
+ begin
105
+ load_hens(*hen.dependencies)
106
+ rescue LoadError => err
107
+ warn "#{name}: Required dependency missing: " <<
108
+ File.basename(err.to_s, '.rake') if verbose
109
+ next
110
+ end
111
+
112
+ hen.lay!
113
+ }
114
+ end
115
+
116
+ # call-seq:
117
+ # add_hen(hen, overwrite = false)
118
+ #
119
+ # Adds +hen+ to the global container. Overwrites
120
+ # an existing hen only if +overwrite+ is true.
121
+ def add_hen(hen, overwrite = false)
122
+ if overwrite
123
+ @hens[hen.name] = hen
124
+ else
125
+ @hens[hen.name] ||= hen
126
+ end
127
+ end
128
+
129
+ # call-seq:
130
+ # Hen[hen] => aHen
131
+ #
132
+ # Get hen by name.
133
+ def [](hen)
134
+ @hens[hen]
135
+ end
136
+
137
+ # call-seq:
138
+ # henrc => aString
139
+ #
140
+ # The path to the user's .henrc
141
+ def henrc(location_only = false)
142
+ @henrc ||= find_henrc(location_only)
143
+ end
144
+
145
+ # call-seq:
146
+ # config => aHash
147
+ # config(key) => aValue
148
+ #
149
+ # The configuration resulting from the user's .henrc. Takes optional
150
+ # +key+ argument as "path" into the config hash, returning the thusly
151
+ # retrieved value.
152
+ #
153
+ # Example:
154
+ # config('a/b/c') #=> @config[:a][:b][:c]
155
+ def config(key = nil)
156
+ @config ||= YAML.load_file(henrc)
157
+ return @config unless key
158
+
159
+ key.split('/').inject(@config) { |value, k|
160
+ value.fetch(k.to_sym)
161
+ }
162
+ rescue IndexError, NoMethodError
163
+ end
164
+
165
+ private
166
+
167
+ # call-seq:
168
+ # find_henrc(location_only = false) => aString
169
+ #
170
+ # Search for a readable .henrc, or, if +location_only+ is true, just return
171
+ # a suitable default location.
172
+ def find_henrc(location_only = false)
173
+ return ENV['HENRC'] || File.join(RCDIRS.last, '.henrc') if location_only
174
+
175
+ if henrc = ENV['HENRC']
176
+ abort "The specified .henrc file could not be found: #{henrc}" \
177
+ unless File.readable?(henrc)
178
+ elsif henrc = RCDIRS.find { |dir|
179
+ h = File.join(dir, '.henrc')
180
+ break h if File.readable?(h)
181
+ }
182
+ else
183
+ abort "No .henrc file could be found! Please " <<
184
+ "create one first by running 'hen config'."
185
+ end
186
+
187
+ henrc
188
+ end
189
+
190
+ # call-seq:
191
+ # load_hens(*hens)
192
+ # load_hens(*hens) { |hen_name| ... }
193
+ #
194
+ # Actually loads the hen files for +hens+, or all available if none are
195
+ # specified. If a block is given, only those hen files are loaded for
196
+ # which the block evaluates to true.
197
+ def load_hens(*hens, &block)
198
+ # By default, include all
199
+ block ||= lambda { |_| true }
200
+
201
+ (hens.empty? ? HENS.keys : hens).each { |hen|
202
+ hen = hen.to_s
203
+ next unless block[hen]
204
+
205
+ HENS[hen].each { |h| load h }
206
+ }
207
+ end
208
+
209
+ end
210
+
211
+ extend Forwardable
212
+
213
+ # Forward to the class
214
+ def_delegators self, :verbose
215
+
216
+ attr_reader :name, :dependencies, :block
217
+
218
+ # call-seq:
219
+ # new(args, overwrite = false) { ... }
220
+ #
221
+ # Creates a new Hen instance of a certain name and optional
222
+ # dependencies; see #resolve_args for details on the +args+
223
+ # argument. Requires a definition block; see #lay! for details.
224
+ #
225
+ # Adds itself to the global hen container via add_hen.
226
+ def initialize(args, overwrite = false, &block)
227
+ @name, @dependencies = resolve_args(args)
228
+
229
+ unless @block = block
230
+ raise LocalJumpError, "#{@name}: no block given" if verbose
231
+ return
232
+ end
233
+
234
+ self.class.add_hen(self, overwrite)
235
+ end
236
+
237
+ # call-seq:
238
+ # hen.lay!
239
+ #
240
+ # Runs the definition block, exposing helper methods from the DSL.
241
+ def lay!
242
+ return if laid?
243
+
244
+ # Call dependencies first
245
+ dependencies.each { |hen|
246
+ self.class[hen].lay!
247
+ }
248
+
249
+ block.bind(DSL).call
250
+ rescue => err
251
+ warn "#{name}: #{err} (#{err.class})" if verbose
252
+ end
253
+
254
+ private
255
+
256
+ # call-seq:
257
+ # resolve_args(args) => [name, dependencies]
258
+ #
259
+ # Splits into hen name and optional dependencies: +args+ may be a single
260
+ # symbol (or string), or a hash with a single key pointing to a list of
261
+ # hens this one depends upon.
262
+ def resolve_args(args)
263
+ name, dependencies = case args
264
+ when Hash
265
+ raise ArgumentError, "Too many hen names: #{args.keys.join(' ')}" \
266
+ if args.size > 1
267
+ raise ArgumentError, 'No hen name given' \
268
+ if args.size < 1
269
+
270
+ [args.keys.first, [*args.values.first]]
271
+ else
272
+ [args, []]
273
+ end
274
+
275
+ [name.to_sym, dependencies.map { |d| d.to_sym }]
276
+ end
277
+
278
+ # call-seq:
279
+ # laid? => true or false
280
+ #
281
+ # Keeps track of whether the block has already been executed.
282
+ def laid?
283
+ return @laid if @laid
284
+
285
+ @laid = true
286
+ false
287
+ end
288
+
289
+ end
290
+
291
+ # call-seq:
292
+ # Hen(args) { ... }
293
+ #
294
+ # Just forwards to Hen.new.
295
+ def Hen(args, &block)
296
+ Hen.new(args, &block)
297
+ end
298
+
299
+ # call-seq:
300
+ # Hen!(args) { ... }
301
+ #
302
+ # Same as above, but overwrites any existing hen with the same name.
303
+ def Hen!(args, &block)
304
+ Hen.new(args, true, &block)
305
+ end
data/lib/hens/gem.rake ADDED
@@ -0,0 +1,129 @@
1
+ Hen :gem => :rdoc do
2
+ # Dependencies:
3
+ # * rdoc -- Uses RDOC_OPTIONS and 'publish_docs' task
4
+
5
+ require 'rake/gempackagetask'
6
+
7
+ gem_options = config[:gem]
8
+ rf_config = config[:rubyforge]
9
+
10
+ if Object.const_defined?(:RDOC_OPTIONS)
11
+ gem_options[:rdoc_options] ||= RDOC_OPTIONS[:options]
12
+ rdoc_files = RDOC_OPTIONS[:rdoc_files]
13
+ end
14
+
15
+ gem_spec = Gem::Specification.new { |spec|
16
+
17
+ ### name
18
+
19
+ gem_options[:name] ||= rf_config[:package]
20
+
21
+ abort 'Gem name missing' unless gem_options[:name]
22
+
23
+ ### version
24
+
25
+ abort 'Gem version missing' unless gem_options[:version]
26
+
27
+ if gem_options.delete(:append_svnversion) && svnversion = `svnversion`[/\d+/]
28
+ gem_options[:version] << '.' << svnversion
29
+ end
30
+
31
+ ### author(s)
32
+
33
+ if author = gem_options.delete(:author)
34
+ gem_options[:authors] ||= [author]
35
+ end
36
+
37
+ ### description
38
+
39
+ gem_options[:description] ||= gem_options[:summary]
40
+
41
+ ### rubyforge project, homepage
42
+
43
+ gem_options[:rubyforge_project] ||= rf_config[:project]
44
+
45
+ if rf_project = gem_options[:rubyforge_project]
46
+ rdoc_dir = rf_config[:rdoc_dir] == :package ?
47
+ rf_config[:package] || gem_options[:name] : RDOC_OPTIONS[:rdoc_dir]
48
+
49
+ gem_options[:homepage] ||= "#{rf_project}.rubyforge.org/#{rdoc_dir}"
50
+ end
51
+
52
+ if gem_options[:homepage] && gem_options[:homepage] !~ %r{://}
53
+ gem_options[:homepage] = 'http://' << gem_options[:homepage]
54
+ end
55
+
56
+ ### extra_rdoc_files, files, executables, bindir
57
+
58
+ gem_options[:files] ||= []
59
+ gem_options[:extra_rdoc_files] ||= rdoc_files - gem_options[:files] if rdoc_files
60
+ gem_options[:files] += gem_options.delete(:extra_files) || []
61
+
62
+ gem_options[:executables] ||= gem_options[:files].grep(/\Abin\//)
63
+
64
+ [:extra_rdoc_files, :files, :executables].each { |files|
65
+ gem_options[files].delete_if { |file| !File.exists?(file) }
66
+ }
67
+
68
+ unless gem_options[:executables].empty?
69
+ gem_options[:bindir] ||= File.dirname(gem_options[:executables].first)
70
+ gem_options[:executables].map! { |executable| File.basename(executable) }
71
+ end
72
+
73
+ ### dependencies
74
+
75
+ (gem_options.delete(:dependencies) || []).each { |dependency|
76
+ spec.add_dependency(*dependency)
77
+ }
78
+
79
+ ### => set options!
80
+
81
+ gem_options.each { |option, value|
82
+ spec.send("#{option}=", value)
83
+ }
84
+ }
85
+
86
+ desc 'Display the gem specification'
87
+ task :gemspec do
88
+ puts gem_spec.to_ruby
89
+ end
90
+
91
+ desc "Update (or create) the project's gemspec file"
92
+ task 'gemspec:update' do
93
+ file = "#{gem_spec.name}.gemspec"
94
+ action = File.exists?(file) ? 'Updated' : 'Created'
95
+
96
+ File.open(file, 'w') { |f| f.puts gem_spec.to_ruby }
97
+
98
+ puts "#{action} #{file}"
99
+ end
100
+
101
+ pkg_task = Rake::GemPackageTask.new(gem_spec) do |pkg|
102
+ pkg.need_tar_gz = true
103
+ pkg.need_zip = true
104
+ end
105
+
106
+ rubyforge do |rf_config, rf_pool|
107
+
108
+ desc 'Package and upload the release to Rubyforge'
109
+ task :release => [:package, :publish_docs] do
110
+ files = Dir[File.join('pkg', "#{pkg_task.package_name}.*")]
111
+ abort 'Nothing to release!' if files.empty?
112
+
113
+ # shorten to (at most) three digits
114
+ version = pkg_task.version.to_s.split(/([.])/)[0..4].join
115
+
116
+ rf = rf_pool.call
117
+
118
+ # TODO: Add release notes and changes.
119
+ #uc = rf.userconfig
120
+ #uc['release_notes'] = description if description
121
+ #uc['release_changes'] = changes if changes
122
+ #uc['preformatted'] = true
123
+
124
+ rf.add_release rf_config[:project], pkg_task.name, version, *files
125
+ end
126
+
127
+ end
128
+
129
+ end
@@ -0,0 +1,79 @@
1
+ Hen :rdoc do
2
+
3
+ require 'rake/rdoctask'
4
+
5
+ rdoc_options = config[:rdoc]
6
+
7
+ if rf_package = config[:rubyforge][:package]
8
+ rdoc_options[:title] ||= "#{rf_package} Application documentation"
9
+ end
10
+
11
+ ### rdoc_dir
12
+
13
+ rdoc_dir = rdoc_options.delete(:rdoc_dir)
14
+
15
+ ### rdoc_files
16
+
17
+ rdoc_files = FileList[rdoc_options.delete(:rdoc_files)].
18
+ sort.uniq.select { |file| File.exists?(file) }
19
+
20
+ ### rdoc_options
21
+
22
+ rdoc_options.delete(:main) unless rdoc_files.include?(rdoc_options[:main])
23
+
24
+ rdoc_options = rdoc_options.map { |option, value|
25
+ option = '--' << option.to_s.tr('_', '-')
26
+ value.is_a?(String) ? [option, value] : value ? option : nil
27
+ }.compact.flatten
28
+
29
+ # Make settings available to other hens
30
+ RDOC_OPTIONS = {
31
+ :rdoc_dir => rdoc_dir,
32
+ :rdoc_files => rdoc_files,
33
+ :options => rdoc_options
34
+ }
35
+
36
+ unless rdoc_files.empty?
37
+ rdoc_task = Rake::RDocTask.new(:doc) { |rdoc|
38
+ rdoc.rdoc_dir = rdoc_dir
39
+ rdoc.rdoc_files = rdoc_files
40
+ rdoc.options = rdoc_options
41
+ }
42
+ else
43
+ task :doc do
44
+ warn 'No files to generate documentation for!'
45
+ end
46
+ end
47
+
48
+ rubyforge do |rf_config|
49
+
50
+ desc 'Publish RDoc to Rubyforge'
51
+ task :publish_docs => :doc do
52
+ rf_project = rf_config[:project]
53
+ abort 'Rubyforge project name missing' unless rf_project
54
+
55
+ rf_user = rf_config[:username]
56
+ abort 'Rubyforge user name missing' unless rf_user
57
+
58
+ rf_host = "#{rf_user}@rubyforge.org"
59
+
60
+ local_dir = rdoc_task.rdoc_dir
61
+ remote_dir = "/var/www/gforge-projects/#{rf_project}"
62
+
63
+ if rdoc_dir = rf_config[:rdoc_dir]
64
+ if rf_package = rf_config[:package]
65
+ rdoc_dir = rf_package if rdoc_dir == :package
66
+ end
67
+
68
+ remote_dir = File.join(remote_dir, rdoc_dir)
69
+ end
70
+
71
+ execute(
72
+ "rsync -av --delete #{local_dir}/ #{rf_host}:#{remote_dir}/",
73
+ "scp -r #{local_dir}/ #{rf_host}:#{remote_dir}/"
74
+ )
75
+ end
76
+
77
+ end
78
+
79
+ end
@@ -0,0 +1,36 @@
1
+ Hen :spec do
2
+
3
+ require 'spec/rake/spectask'
4
+
5
+ spec_options = config[:spec]
6
+
7
+ spec_files = spec_options.delete(:files) || FileList[spec_options.delete(:pattern)]
8
+
9
+ if spec_files && !spec_files.empty?
10
+ if spec_helper = spec_options.delete(:helper) and File.readable?(spec_helper)
11
+ spec_files.delete(spec_helper)
12
+ spec_files.unshift(spec_helper)
13
+ end
14
+
15
+ spec_opts = spec_options.map { |option, value|
16
+ option = '--' << option.to_s.tr('_', '-')
17
+ value.is_a?(String) ? [option, value] : value ? option : nil
18
+ }.compact.flatten
19
+
20
+ spec_task = lambda { |t|
21
+ t.spec_files = spec_files
22
+ t.spec_opts = spec_opts
23
+ }
24
+
25
+ Spec::Rake::SpecTask.new(&spec_task)
26
+
27
+ #desc "Run specs with RCov"
28
+ Spec::Rake::SpecTask.new('spec:rcov') do |t|
29
+ spec_task[t]
30
+
31
+ t.rcov = true
32
+ t.rcov_opts = ['--exclude', spec_files.join(',')]
33
+ end
34
+ end
35
+
36
+ end
@@ -0,0 +1,19 @@
1
+ Hen :test do
2
+
3
+ require 'rake/testtask'
4
+
5
+ test_options = config[:test]
6
+
7
+ test_files = test_options.delete(:files) || FileList[test_options.delete(:pattern)]
8
+
9
+ if test_files && !test_files.empty?
10
+ Rake::TestTask.new { |t|
11
+ t.test_files = test_files
12
+
13
+ test_options.each { |option, value|
14
+ t.send("#{option}=", value)
15
+ }
16
+ }
17
+ end
18
+
19
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: blackwinter-hen
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.5
5
+ platform: ruby
6
+ authors:
7
+ - Jens Wille
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-22 00:00:00 -08:00
13
+ default_executable: hen
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rubyforge
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: ruby-nuggets
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: 0.3.3
32
+ version:
33
+ description: Hoe or Echoe? No, thanks! Just a Rake helper that fits my own personal style.
34
+ email: jens.wille@uni-koeln.de
35
+ executables:
36
+ - hen
37
+ extensions: []
38
+
39
+ extra_rdoc_files:
40
+ - COPYING
41
+ - ChangeLog
42
+ - README
43
+ files:
44
+ - lib/hen.rb
45
+ - lib/hen/cli.rb
46
+ - lib/hen/dsl.rb
47
+ - lib/hen/version.rb
48
+ - bin/hen
49
+ - Rakefile
50
+ - COPYING
51
+ - ChangeLog
52
+ - README
53
+ - lib/hens/rdoc.rake
54
+ - lib/hens/gem.rake
55
+ - lib/hens/test.rake
56
+ - lib/hens/spec.rake
57
+ - example/hens
58
+ - example/hens/sample.rake
59
+ - example/project
60
+ - example/project/Rakefile
61
+ - example/project/COPYING
62
+ - example/project/ChangeLog
63
+ - example/project/lib
64
+ - example/project/lib/__progname__
65
+ - example/project/lib/__progname__/version.rb
66
+ - example/project/lib/__progname__.rb
67
+ - example/project/README
68
+ - example/.henrc
69
+ has_rdoc: true
70
+ homepage: http://prometheus.rubyforge.org/hen
71
+ post_install_message:
72
+ rdoc_options:
73
+ - --inline-source
74
+ - --title
75
+ - hen Application documentation
76
+ - --charset
77
+ - UTF-8
78
+ - --main
79
+ - README
80
+ - --all
81
+ - --line-numbers
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: "0"
89
+ version:
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: "0"
95
+ version:
96
+ requirements: []
97
+
98
+ rubyforge_project: prometheus
99
+ rubygems_version: 1.2.0
100
+ signing_key:
101
+ specification_version: 2
102
+ summary: Hoe or Echoe? No, thanks! Just a Rake helper that fits my own personal style.
103
+ test_files: []
104
+