inochi 0.2.0 → 0.3.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.
- data/LICENSE +2 -0
- data/bin/inochi +30 -29
- data/doc/api/Inochi.html +439 -323
- data/doc/api/Inochi/Manual.html +230 -0
- data/doc/api/Inochi/Phrases.html +409 -0
- data/doc/api/Inochi/Version.html +222 -0
- data/doc/api/all-methods.html +97 -9
- data/doc/api/all-namespaces.html +7 -1
- data/doc/api/readme.html +3 -0
- data/doc/history.erb +50 -20
- data/doc/index.xhtml +355 -141
- data/doc/intro.erb +14 -14
- data/doc/setup.erb +8 -7
- data/doc/usage.erb +110 -5
- data/lib/inochi.rb +14 -3
- data/lib/inochi/book.rb +84 -0
- data/lib/inochi/init.rb +239 -0
- data/lib/inochi/main.rb +75 -0
- data/lib/inochi/rake.rb +777 -0
- data/lib/inochi/util.rb +77 -0
- data/test/{inochi/inochi.rb → inochi.rb} +0 -0
- metadata +32 -5
- data/lib/inochi/inochi.rb +0 -1064
data/lib/inochi/util.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
class << Inochi
|
2
|
+
##
|
3
|
+
# Returns the name of the main program executable, which
|
4
|
+
# is the same as the project name fully in lowercase.
|
5
|
+
#
|
6
|
+
def calc_program_name project_symbol
|
7
|
+
camel_to_snake_case(project_symbol).downcase
|
8
|
+
end
|
9
|
+
|
10
|
+
##
|
11
|
+
# Calculates the name of the project module from the given project name.
|
12
|
+
#
|
13
|
+
def calc_project_symbol project_name
|
14
|
+
name = project_name.to_s.gsub(/\W+/, '_').squeeze('_').gsub(/^_|_$/, '')
|
15
|
+
(name[0,1].upcase + name[1..-1]).to_sym
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# Transforms the given input from CamelCase to snake_case.
|
20
|
+
#
|
21
|
+
def camel_to_snake_case input
|
22
|
+
input = input.to_s.dup
|
23
|
+
|
24
|
+
# handle camel case like FooBar => Foo_Bar
|
25
|
+
while input.gsub!(/([a-z]+)([A-Z])(\w+)/) { $1 + '_' + $2 + $3 }
|
26
|
+
end
|
27
|
+
|
28
|
+
# handle abbreviations like XMLParser => XML_Parser
|
29
|
+
while input.gsub!(/([A-Z]+)([A-Z])([a-z]+)/) { $1 + '_' + $2 + $3 }
|
30
|
+
end
|
31
|
+
|
32
|
+
input
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
INOCHI_LIBRARY_PATH = File.dirname(__FILE__)
|
38
|
+
|
39
|
+
##
|
40
|
+
# Returns the path of the first file outside
|
41
|
+
# Inochi's core from which this method was called.
|
42
|
+
#
|
43
|
+
def first_caller_file
|
44
|
+
caller.each do |step|
|
45
|
+
if file = step[/^.+(?=:\d+$)/]
|
46
|
+
file = File.expand_path(file)
|
47
|
+
base = File.dirname(file)
|
48
|
+
|
49
|
+
break file unless base.index(INOCHI_LIBRARY_PATH) == 0
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Returns the project module corresponding to the given symbol.
|
56
|
+
# A new module is created if none already exists.
|
57
|
+
#
|
58
|
+
def fetch_project_module project_symbol
|
59
|
+
if Object.const_defined? project_symbol
|
60
|
+
project_module = Object.const_get(project_symbol)
|
61
|
+
else
|
62
|
+
project_module = Module.new
|
63
|
+
Object.const_set project_symbol, project_module
|
64
|
+
end
|
65
|
+
|
66
|
+
project_module
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
unless File.respond_to? :write
|
71
|
+
##
|
72
|
+
# Writes the given content to the given file.
|
73
|
+
#
|
74
|
+
def File.write path, content
|
75
|
+
open(path, 'wb') {|f| f.write content }
|
76
|
+
end
|
77
|
+
end
|
File without changes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inochi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Suraj N. Kurapati
|
@@ -9,9 +9,19 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-02-12 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: erbook
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ~>
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "6"
|
24
|
+
version:
|
15
25
|
- !ruby/object:Gem::Dependency
|
16
26
|
name: minitest
|
17
27
|
type: :runtime
|
@@ -55,6 +65,16 @@ dependencies:
|
|
55
65
|
- !ruby/object:Gem::Version
|
56
66
|
version: "0"
|
57
67
|
version:
|
68
|
+
- !ruby/object:Gem::Dependency
|
69
|
+
name: babelfish
|
70
|
+
type: :runtime
|
71
|
+
version_requirement:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: "0"
|
77
|
+
version:
|
58
78
|
- !ruby/object:Gem::Dependency
|
59
79
|
name: yard
|
60
80
|
type: :runtime
|
@@ -105,12 +125,15 @@ extra_rdoc_files: []
|
|
105
125
|
|
106
126
|
files:
|
107
127
|
- test
|
108
|
-
- test/inochi
|
109
|
-
- test/inochi/inochi.rb
|
128
|
+
- test/inochi.rb
|
110
129
|
- lib
|
111
130
|
- lib/inochi.rb
|
112
131
|
- lib/inochi
|
113
|
-
- lib/inochi/
|
132
|
+
- lib/inochi/main.rb
|
133
|
+
- lib/inochi/book.rb
|
134
|
+
- lib/inochi/rake.rb
|
135
|
+
- lib/inochi/util.rb
|
136
|
+
- lib/inochi/init.rb
|
114
137
|
- Rakefile
|
115
138
|
- bin
|
116
139
|
- bin/inochi
|
@@ -130,6 +153,10 @@ files:
|
|
130
153
|
- doc/api/app.js
|
131
154
|
- doc/api/readme.html
|
132
155
|
- doc/api/all-namespaces.html
|
156
|
+
- doc/api/Inochi
|
157
|
+
- doc/api/Inochi/Phrases.html
|
158
|
+
- doc/api/Inochi/Manual.html
|
159
|
+
- doc/api/Inochi/Version.html
|
133
160
|
- doc/api/index.html
|
134
161
|
- doc/api/Inochi.html
|
135
162
|
- doc/usage.erb
|
data/lib/inochi/inochi.rb
DELETED
@@ -1,1064 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
|
3
|
-
module Inochi
|
4
|
-
class << self
|
5
|
-
##
|
6
|
-
# Establishes your project in Ruby's runtime environment by defining
|
7
|
-
# the project module (which serves as a namespace for all code in the
|
8
|
-
# project) and providing a common configuration for the project module:
|
9
|
-
#
|
10
|
-
# * Adds the project lib/ directory to the Ruby load path.
|
11
|
-
#
|
12
|
-
# * Defines the INOCHI constant in the project module. This constant
|
13
|
-
# contains the effective configuration parameters (@see project_config).
|
14
|
-
#
|
15
|
-
# * Defines all configuration parameters as constants in the project module.
|
16
|
-
#
|
17
|
-
# This method must be invoked from immediately within (that is, not from
|
18
|
-
# within any of its descendant directories) the project lib/ directory.
|
19
|
-
# Ideally, this method would be invoked from the main project library.
|
20
|
-
#
|
21
|
-
# @param [Symbol] project_symbol
|
22
|
-
# Name of the Ruby constant which serves
|
23
|
-
# as a namespace for the entire project.
|
24
|
-
#
|
25
|
-
# @param [Hash] project_config
|
26
|
-
# Project configuration parameters:
|
27
|
-
#
|
28
|
-
# [String] :project =>
|
29
|
-
# Name of the project.
|
30
|
-
#
|
31
|
-
# The default value is the value of the project_symbol parameter.
|
32
|
-
#
|
33
|
-
# [String] :tagline =>
|
34
|
-
# An enticing, single line description of the project.
|
35
|
-
#
|
36
|
-
# The default value is an empty string.
|
37
|
-
#
|
38
|
-
# [String] :website =>
|
39
|
-
# URL of the published project website.
|
40
|
-
#
|
41
|
-
# The default value is an empty string.
|
42
|
-
#
|
43
|
-
# [String] :docsite =>
|
44
|
-
# URL of the published user manual.
|
45
|
-
#
|
46
|
-
# The default value is the same value as the :website parameter.
|
47
|
-
#
|
48
|
-
# [String] :program =>
|
49
|
-
# Name of the main project executable.
|
50
|
-
#
|
51
|
-
# The default value is the value of the :project parameter
|
52
|
-
# in lowercase and CamelCase converted into snake_case.
|
53
|
-
#
|
54
|
-
# [String] :version =>
|
55
|
-
# Version of the project.
|
56
|
-
#
|
57
|
-
# The default value is "0.0.0".
|
58
|
-
#
|
59
|
-
# [String] :release =>
|
60
|
-
# Date when this version was released.
|
61
|
-
#
|
62
|
-
# The default value is the current time.
|
63
|
-
#
|
64
|
-
# [String] :display =>
|
65
|
-
# How the project name should be displayed.
|
66
|
-
#
|
67
|
-
# The default value is the project name and version together.
|
68
|
-
#
|
69
|
-
# [String] :install =>
|
70
|
-
# Path to the directory which contains the project.
|
71
|
-
#
|
72
|
-
# The default value is one directory above the parent
|
73
|
-
# directory of the file from which this method was called.
|
74
|
-
#
|
75
|
-
# [Hash] :require =>
|
76
|
-
# The names and version constraints of ruby gems required by
|
77
|
-
# this project. This information must be expressed as follows:
|
78
|
-
#
|
79
|
-
# * Each hash key must be the name of a ruby gem.
|
80
|
-
#
|
81
|
-
# * Each hash value must be either +nil+, a single version number
|
82
|
-
# requirement string (see Gem::Requirement) or an Array thereof.
|
83
|
-
#
|
84
|
-
# The default value is an empty Hash.
|
85
|
-
#
|
86
|
-
# @return [Module] The newly configured project module.
|
87
|
-
#
|
88
|
-
def init project_symbol, project_config = {}
|
89
|
-
project_module = fetch_project_module(project_symbol)
|
90
|
-
|
91
|
-
# this method is not re-entrant
|
92
|
-
@already_seen ||= []
|
93
|
-
return project_module if @already_seen.include? project_module
|
94
|
-
@already_seen << project_module
|
95
|
-
|
96
|
-
# put project on Ruby load path
|
97
|
-
project_file = File.expand_path(first_caller_file)
|
98
|
-
project_libs = File.dirname(project_file)
|
99
|
-
$LOAD_PATH << project_libs unless $LOAD_PATH.include? project_libs
|
100
|
-
|
101
|
-
# supply configuration defaults
|
102
|
-
project_config[:project] ||= project_symbol.to_s
|
103
|
-
project_config[:tagline] ||= ''
|
104
|
-
project_config[:version] ||= '0.0.0'
|
105
|
-
project_config[:release] ||= Time.now.strftime('%F')
|
106
|
-
project_config[:website] ||= ''
|
107
|
-
project_config[:docsite] ||= project_config[:website]
|
108
|
-
project_config[:display] ||= "#{project_config[:project]} #{project_config[:version]}"
|
109
|
-
project_config[:program] ||= calc_program_name(project_symbol)
|
110
|
-
project_config[:install] ||= File.dirname(project_libs)
|
111
|
-
project_config[:require] ||= {}
|
112
|
-
|
113
|
-
# establish gem version dependencies and
|
114
|
-
# sanitize the values while we're at it
|
115
|
-
src = project_config[:require].dup
|
116
|
-
dst = project_config[:require].clear
|
117
|
-
|
118
|
-
src.each_pair do |gem_name, version_reqs|
|
119
|
-
gem_name = gem_name.to_s
|
120
|
-
version_reqs = [version_reqs].flatten.compact
|
121
|
-
|
122
|
-
dst[gem_name] = version_reqs
|
123
|
-
gem gem_name, *version_reqs
|
124
|
-
end
|
125
|
-
|
126
|
-
# make configuration parameters available as constants
|
127
|
-
project_config[:inochi] = project_config
|
128
|
-
|
129
|
-
class << project_config[:version]
|
130
|
-
# Returns the major number in this version.
|
131
|
-
def major
|
132
|
-
to_s[/^\d+/]
|
133
|
-
end
|
134
|
-
|
135
|
-
# Returns a string describing any version with the current major number.
|
136
|
-
def series
|
137
|
-
"#{major}.x.x"
|
138
|
-
end
|
139
|
-
|
140
|
-
# Returns a Gem::Requirement expression.
|
141
|
-
def requirement
|
142
|
-
"~> #{major}"
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
project_config.each_pair do |param, value|
|
147
|
-
project_module.const_set param.to_s.upcase, value
|
148
|
-
end
|
149
|
-
|
150
|
-
project_module
|
151
|
-
end
|
152
|
-
|
153
|
-
##
|
154
|
-
# Provides a common configuration for the main project executable:
|
155
|
-
#
|
156
|
-
# * The program description (the sequence of non-blank lines at the
|
157
|
-
# top of the file in which this method is invoked) is properly
|
158
|
-
# formatted and displayed at the top of program's help information.
|
159
|
-
#
|
160
|
-
# * The program version information is fetched from the project module
|
161
|
-
# and formatted in YAML fashion for easy consumption by other tools.
|
162
|
-
#
|
163
|
-
# * A list of command-line options is displayed at
|
164
|
-
# the bottom of the program's help information.
|
165
|
-
#
|
166
|
-
# It is assumed that this method is invoked from only within
|
167
|
-
# the main project executable (in the project bin/ directory).
|
168
|
-
#
|
169
|
-
# @param [Symbol] project_symbol
|
170
|
-
# Name of the Ruby constant which serves
|
171
|
-
# as a namespace for the entire project.
|
172
|
-
#
|
173
|
-
# @param trollop_args
|
174
|
-
# Optional arguments for Trollop::options().
|
175
|
-
#
|
176
|
-
# @param trollop_config
|
177
|
-
# Optional block argument for Trollop::options().
|
178
|
-
#
|
179
|
-
# @return The result of Trollop::options().
|
180
|
-
#
|
181
|
-
def main project_symbol, *trollop_args, &trollop_config
|
182
|
-
program_file = first_caller_file
|
183
|
-
program_name = File.basename(program_file)
|
184
|
-
program_home = File.dirname(File.dirname(program_file))
|
185
|
-
|
186
|
-
# load the project module
|
187
|
-
require File.join(program_home, 'lib', program_name)
|
188
|
-
project_module = fetch_project_module(project_symbol)
|
189
|
-
|
190
|
-
# parse command-line options
|
191
|
-
require 'trollop'
|
192
|
-
|
193
|
-
options = Trollop.options(*trollop_args) do
|
194
|
-
|
195
|
-
# show project description
|
196
|
-
text "#{project_module::PROJECT} - #{project_module::TAGLINE}"
|
197
|
-
text ''
|
198
|
-
|
199
|
-
# show program description
|
200
|
-
text File.read(program_file)[/\A.*?^$\n/m]. # grab the header
|
201
|
-
gsub(/^# ?/, ''). # strip the comment markers
|
202
|
-
sub(/\A!.*?\n/, '').lstrip # omit the shebang line
|
203
|
-
text ''
|
204
|
-
|
205
|
-
instance_eval(&trollop_config) if trollop_config
|
206
|
-
|
207
|
-
# show version information
|
208
|
-
version %w[PROJECT VERSION RELEASE WEBSITE INSTALL].map {|c|
|
209
|
-
"#{c.downcase}: #{project_module.const_get c}"
|
210
|
-
}.join("\n")
|
211
|
-
|
212
|
-
opt :manual, 'Show the user manual'
|
213
|
-
end
|
214
|
-
|
215
|
-
if options[:manual]
|
216
|
-
require 'launchy'
|
217
|
-
Launchy::Browser.run "#{project_module::INSTALL}/doc/index.xhtml"
|
218
|
-
exit
|
219
|
-
end
|
220
|
-
|
221
|
-
options
|
222
|
-
end
|
223
|
-
|
224
|
-
##
|
225
|
-
# Provides Rake tasks for packaging, publishing, and announcing your project.
|
226
|
-
#
|
227
|
-
# * An AUTHORS constant (which has the form "[[name, info]]"
|
228
|
-
# where "name" is the name of a copyright holder and "info" is
|
229
|
-
# their contact information) is added to the project module.
|
230
|
-
#
|
231
|
-
# Unless this information is supplied via the :authors option,
|
232
|
-
# it is automatically extracted from copyright notices in the
|
233
|
-
# project license file, where the first copyright notice is
|
234
|
-
# expected to correspond to the primary project maintainer.
|
235
|
-
#
|
236
|
-
# Copyright notices must be in the following form:
|
237
|
-
#
|
238
|
-
# Copyright YEAR HOLDER <EMAIL>
|
239
|
-
#
|
240
|
-
# Where HOLDER is the name of the copyright holder, YEAR is the year
|
241
|
-
# when the copyright holder first began working on the project, and
|
242
|
-
# EMAIL is (optional) the email address of the copyright holder.
|
243
|
-
#
|
244
|
-
# @param [Symbol] project_symbol
|
245
|
-
# Name of the Ruby constant which serves
|
246
|
-
# as a namespace for the entire project.
|
247
|
-
#
|
248
|
-
# @param [Hash] options
|
249
|
-
# Additional method parameters, which are all optional:
|
250
|
-
#
|
251
|
-
# [Array] :authors =>
|
252
|
-
# A list of project authors and their contact information. This
|
253
|
-
# list must have the form "[[name, info]]" where "name" is the name
|
254
|
-
# of a project author and "info" is their contact information.
|
255
|
-
#
|
256
|
-
# [String] :license_file =>
|
257
|
-
# Path (relative to the main project directory which contains the
|
258
|
-
# project Rakefile) to the file which contains the project license.
|
259
|
-
#
|
260
|
-
# The default value is "LICENSE".
|
261
|
-
#
|
262
|
-
# [String] :logins_file =>
|
263
|
-
# Path to the YAML file which contains login
|
264
|
-
# information for publishing release announcements.
|
265
|
-
#
|
266
|
-
# The default value is "~/.config/inochi/logins.yaml"
|
267
|
-
# where "~" is the path to your home directory.
|
268
|
-
#
|
269
|
-
# [String] :rubyforge_project =>
|
270
|
-
# Name of the RubyForge project where
|
271
|
-
# release packages will be published.
|
272
|
-
#
|
273
|
-
# The default value is the value of the PROGRAM constant.
|
274
|
-
#
|
275
|
-
# [String] :rubyforge_section =>
|
276
|
-
# Name of the RubyForge project's File Release System
|
277
|
-
# section where release packages will be published.
|
278
|
-
#
|
279
|
-
# The default value is the value of the :rubyforge_project parameter.
|
280
|
-
#
|
281
|
-
# [String] :raa_project =>
|
282
|
-
# Name of the RAA (Ruby Application Archive) entry for this project.
|
283
|
-
#
|
284
|
-
# The default value is the value of the PROGRAM constant.
|
285
|
-
#
|
286
|
-
# [String] :upload_target =>
|
287
|
-
# Where to upload the project documentation.
|
288
|
-
# See "destination" in the rsync manual.
|
289
|
-
#
|
290
|
-
# The default value is nil.
|
291
|
-
#
|
292
|
-
# [String] :upload_delete =>
|
293
|
-
# Delete unknown files at the upload target location?
|
294
|
-
#
|
295
|
-
# The default value is false.
|
296
|
-
#
|
297
|
-
# [Array] :upload_options =>
|
298
|
-
# Additional command-line arguments to the rsync command.
|
299
|
-
#
|
300
|
-
# The default value is an empty array.
|
301
|
-
#
|
302
|
-
# @param gem_config
|
303
|
-
# Block that is passed to Gem::specification.new()
|
304
|
-
# for additonal gem configuration.
|
305
|
-
#
|
306
|
-
# @yieldparam [Gem::Specification] gem_spec the gem specification
|
307
|
-
#
|
308
|
-
def rake project_symbol, options = {}, &gem_config
|
309
|
-
program_file = first_caller_file
|
310
|
-
program_home = File.dirname(program_file)
|
311
|
-
|
312
|
-
# load the project module
|
313
|
-
program_name = File.basename(program_home)
|
314
|
-
project_libs = File.join('lib', program_name)
|
315
|
-
|
316
|
-
require project_libs
|
317
|
-
project_module = fetch_project_module(project_symbol)
|
318
|
-
|
319
|
-
# supply default options
|
320
|
-
options[:rubyforge_project] ||= program_name
|
321
|
-
options[:rubyforge_section] ||= program_name
|
322
|
-
options[:raa_project] ||= program_name
|
323
|
-
options[:license_file] ||= 'LICENSE'
|
324
|
-
options[:logins_file] ||= File.join(ENV['HOME'], '.config', 'inochi', 'logins.yaml')
|
325
|
-
options[:upload_delete] ||= false
|
326
|
-
options[:upload_options] ||= []
|
327
|
-
|
328
|
-
# add AUTHORS constant to the project module
|
329
|
-
copyright_holders = options[:authors] ||
|
330
|
-
File.read(options[:license_file]).
|
331
|
-
scan(/Copyright.*?\d+\s+(.*)/).flatten.
|
332
|
-
map {|s| (s =~ /\s*<(.*?)>/) ? [$`, $1] : [s, ''] }
|
333
|
-
|
334
|
-
project_module.const_set :AUTHORS, copyright_holders
|
335
|
-
|
336
|
-
require 'rake/clean'
|
337
|
-
|
338
|
-
hide_rake_task = lambda do |name|
|
339
|
-
Rake::Task[name].instance_variable_set :@comment, nil
|
340
|
-
end
|
341
|
-
|
342
|
-
# testing
|
343
|
-
desc 'Run all unit tests.'
|
344
|
-
task :test do
|
345
|
-
ruby '-w', '-I.', '-Ilib', '-r', program_name, '-e', %q{
|
346
|
-
# set title of test suite
|
347
|
-
$0 = File.basename(Dir.pwd)
|
348
|
-
|
349
|
-
require 'minitest/unit'
|
350
|
-
require 'minitest/spec'
|
351
|
-
require 'minitest/mock'
|
352
|
-
MiniTest::Unit.autorun
|
353
|
-
|
354
|
-
Dir['test/**/*.rb'].sort.each do |test|
|
355
|
-
unit = test.sub('test/', 'lib/')
|
356
|
-
|
357
|
-
if File.exist? unit
|
358
|
-
# strip file extension because require()
|
359
|
-
# does not normalize its input and it
|
360
|
-
# will think that the two paths (with &
|
361
|
-
# without file extension) are different
|
362
|
-
unit_path = unit.sub(/\.rb$/, '').sub('lib/', '')
|
363
|
-
test_path = test.sub(/\.rb$/, '')
|
364
|
-
|
365
|
-
require unit_path
|
366
|
-
require test_path
|
367
|
-
else
|
368
|
-
warn "Skipped test #{test.inspect} because it lacks a corresponding #{unit.inspect} unit."
|
369
|
-
end
|
370
|
-
end
|
371
|
-
}
|
372
|
-
end
|
373
|
-
|
374
|
-
# documentation
|
375
|
-
desc 'Build all documentation.'
|
376
|
-
task :doc => %w[ doc:api doc:man ]
|
377
|
-
|
378
|
-
# user manual
|
379
|
-
doc_man_src = 'doc/index.erb'
|
380
|
-
doc_man_dst = 'doc/index.xhtml'
|
381
|
-
doc_man_deps = FileList['doc/*.erb']
|
382
|
-
|
383
|
-
doc_man_doc = nil
|
384
|
-
task :doc_man_doc => doc_man_src do
|
385
|
-
unless doc_man_doc
|
386
|
-
unless project_symbol == :ERBook
|
387
|
-
gem 'erbook', '~> 6'
|
388
|
-
require 'erbook'
|
389
|
-
end
|
390
|
-
|
391
|
-
doc_man_txt = File.read(doc_man_src)
|
392
|
-
doc_man_doc = ERBook::Document.new(:xhtml, doc_man_txt, doc_man_src, :unindent => true)
|
393
|
-
end
|
394
|
-
end
|
395
|
-
|
396
|
-
desc 'Build the user manual.'
|
397
|
-
task 'doc:man' => doc_man_dst
|
398
|
-
|
399
|
-
file doc_man_dst => doc_man_deps do
|
400
|
-
Rake::Task[:doc_man_doc].invoke
|
401
|
-
File.write doc_man_dst, doc_man_doc
|
402
|
-
end
|
403
|
-
|
404
|
-
CLOBBER.include doc_man_dst
|
405
|
-
|
406
|
-
# API reference
|
407
|
-
doc_api_dst = 'doc/api'
|
408
|
-
|
409
|
-
desc 'Build API reference.'
|
410
|
-
task 'doc:api' => doc_api_dst
|
411
|
-
|
412
|
-
require 'yard'
|
413
|
-
YARD::Rake::YardocTask.new doc_api_dst do |t|
|
414
|
-
t.options.push '--protected',
|
415
|
-
'--output-dir', doc_api_dst,
|
416
|
-
'--readme', options[:license_file]
|
417
|
-
|
418
|
-
task doc_api_dst => options[:license_file]
|
419
|
-
end
|
420
|
-
|
421
|
-
hide_rake_task[doc_api_dst]
|
422
|
-
|
423
|
-
CLEAN.include '.yardoc'
|
424
|
-
CLOBBER.include doc_api_dst
|
425
|
-
|
426
|
-
# announcements
|
427
|
-
desc 'Build all release announcements.'
|
428
|
-
task :ann => %w[ ann:feed ann:html ann:text ann:mail ]
|
429
|
-
|
430
|
-
# it has long been a tradition to use an "[ANN]" prefix
|
431
|
-
# when announcing things on the ruby-talk mailing list
|
432
|
-
ann_prefix = '[ANN] '
|
433
|
-
ann_subject = ann_prefix + project_module::DISPLAY
|
434
|
-
ann_project = ann_prefix + project_module::PROJECT
|
435
|
-
|
436
|
-
# fetch the project summary from user manual
|
437
|
-
ann_nfo_doc = nil
|
438
|
-
task :ann_nfo_doc => :doc_man_doc do
|
439
|
-
ann_nfo_doc = $project_summary_node
|
440
|
-
end
|
441
|
-
|
442
|
-
# fetch release notes from user manual
|
443
|
-
ann_rel_doc = nil
|
444
|
-
task :ann_rel_doc => :doc_man_doc do
|
445
|
-
unless ann_rel_doc
|
446
|
-
if parent = $project_history_node
|
447
|
-
if child = parent.children.first
|
448
|
-
ann_rel_doc = child
|
449
|
-
else
|
450
|
-
raise 'The "project_history" node in the user manual lacks child nodes.'
|
451
|
-
end
|
452
|
-
else
|
453
|
-
raise 'The user manual lacks a "project_history" node.'
|
454
|
-
end
|
455
|
-
end
|
456
|
-
end
|
457
|
-
|
458
|
-
# build release notes in HTML and plain text
|
459
|
-
# converts the given HTML into plain text. we do this using
|
460
|
-
# lynx because (1) it outputs a list of all hyperlinks used
|
461
|
-
# in the HTML document and (2) it runs on all major platforms
|
462
|
-
convert_html_to_text = lambda do |html|
|
463
|
-
require 'tempfile'
|
464
|
-
|
465
|
-
begin
|
466
|
-
# lynx's -dump option requires a .html file
|
467
|
-
tmp_file = Tempfile.new(Inochi::PROGRAM).path + '.html'
|
468
|
-
|
469
|
-
File.write tmp_file, html
|
470
|
-
text = `lynx -dump #{tmp_file} -width 70`
|
471
|
-
ensure
|
472
|
-
File.delete tmp_file
|
473
|
-
end
|
474
|
-
|
475
|
-
# improve readability of list items
|
476
|
-
# by adding a blank line between them
|
477
|
-
text.gsub! %r{(\r?\n)( +\* \S)}, '\1\1\2'
|
478
|
-
|
479
|
-
text
|
480
|
-
end
|
481
|
-
|
482
|
-
# binds relative addresses in the given HTML to the project docsite
|
483
|
-
resolve_html_links = lambda do |html|
|
484
|
-
# resolve relative URLs into absolute URLs
|
485
|
-
# see http://en.wikipedia.org/wiki/URI_scheme#Generic_syntax
|
486
|
-
require 'addressable/uri'
|
487
|
-
uri = Addressable::URI.parse(project_module::DOCSITE)
|
488
|
-
doc_url = uri.to_s
|
489
|
-
dir_url = uri.path =~ %r{/$|^$} ? doc_url : File.dirname(doc_url)
|
490
|
-
|
491
|
-
html.to_s.gsub %r{(href=|src=)(.)(.*?)(\2)} do |match|
|
492
|
-
a, b = $1 + $2, $3.to_s << $4
|
493
|
-
|
494
|
-
case $3
|
495
|
-
when %r{^[[:alpha:]][[:alnum:]\+\.\-]*://} # already absolute
|
496
|
-
match
|
497
|
-
|
498
|
-
when /^#/
|
499
|
-
a << File.join(doc_url, b)
|
500
|
-
|
501
|
-
else
|
502
|
-
a << File.join(dir_url, b)
|
503
|
-
end
|
504
|
-
end
|
505
|
-
end
|
506
|
-
|
507
|
-
ann_html = nil
|
508
|
-
task :ann_html => [:doc_man_doc, :ann_nfo_doc, :ann_rel_doc] do
|
509
|
-
unless ann_html
|
510
|
-
ann_html = %{
|
511
|
-
<center>
|
512
|
-
<h1>#{project_module::DISPLAY}</h1>
|
513
|
-
<p>#{project_module::TAGLINE}</p>
|
514
|
-
<p>#{project_module::WEBSITE}</p>
|
515
|
-
</center>
|
516
|
-
#{ann_nfo_doc}
|
517
|
-
#{ann_rel_doc}
|
518
|
-
}
|
519
|
-
|
520
|
-
# remove heading navigation menus
|
521
|
-
ann_html.gsub! %r{<div class="nav"[^>]*>(.*?)</div>}, ''
|
522
|
-
|
523
|
-
# remove latex-style heading numbers
|
524
|
-
ann_html.gsub! %r"(<(h\d)[^>]*>).+?(?: ){2}(.+?)(</\2>)"m, '\1\3\4'
|
525
|
-
|
526
|
-
ann_html = resolve_html_links[ann_html]
|
527
|
-
end
|
528
|
-
end
|
529
|
-
|
530
|
-
ann_text = nil
|
531
|
-
task :ann_text => :ann_html do
|
532
|
-
unless ann_text
|
533
|
-
ann_text = convert_html_to_text[ann_html]
|
534
|
-
end
|
535
|
-
end
|
536
|
-
|
537
|
-
ann_nfo_text = nil
|
538
|
-
task :ann_nfo_text => :ann_nfo_doc do
|
539
|
-
unless ann_nfo_text
|
540
|
-
ann_nfo_html = resolve_html_links[ann_nfo_doc]
|
541
|
-
ann_nfo_text = convert_html_to_text[ann_nfo_html]
|
542
|
-
end
|
543
|
-
end
|
544
|
-
|
545
|
-
# HTML
|
546
|
-
ann_html_dst = 'ANN.html'
|
547
|
-
|
548
|
-
desc "Build HTML announcement: #{ann_html_dst}"
|
549
|
-
task 'ann:html' => ann_html_dst
|
550
|
-
|
551
|
-
file ann_html_dst => doc_man_deps do
|
552
|
-
Rake::Task[:ann_html].invoke
|
553
|
-
File.write ann_html_dst, ann_html
|
554
|
-
end
|
555
|
-
|
556
|
-
CLEAN.include ann_html_dst
|
557
|
-
|
558
|
-
# RSS feed
|
559
|
-
ann_feed_dst = 'doc/ann.xml'
|
560
|
-
|
561
|
-
desc "Build RSS announcement: #{ann_feed_dst}"
|
562
|
-
task 'ann:feed' => ann_feed_dst
|
563
|
-
|
564
|
-
file ann_feed_dst => doc_man_deps do
|
565
|
-
require 'time'
|
566
|
-
require 'rss/maker'
|
567
|
-
|
568
|
-
feed = RSS::Maker.make('2.0') do |feed|
|
569
|
-
feed.channel.title = ann_project
|
570
|
-
feed.channel.link = project_module::WEBSITE
|
571
|
-
feed.channel.description = project_module::TAGLINE
|
572
|
-
|
573
|
-
Rake::Task[:ann_rel_doc].invoke
|
574
|
-
Rake::Task[:ann_html].invoke
|
575
|
-
|
576
|
-
item = feed.items.new_item
|
577
|
-
item.title = ann_rel_doc.title
|
578
|
-
item.link = project_module::DOCSITE + '#' + ann_rel_doc.here_frag
|
579
|
-
item.date = Time.parse(item.title)
|
580
|
-
item.description = ann_html
|
581
|
-
end
|
582
|
-
|
583
|
-
File.write ann_feed_dst, feed
|
584
|
-
end
|
585
|
-
|
586
|
-
CLOBBER.include ann_feed_dst
|
587
|
-
|
588
|
-
# plain text
|
589
|
-
ann_text_dst = 'ANN.txt'
|
590
|
-
|
591
|
-
desc "Build plain text announcement: #{ann_text_dst}"
|
592
|
-
task 'ann:text' => ann_text_dst
|
593
|
-
|
594
|
-
file ann_text_dst => doc_man_deps do
|
595
|
-
Rake::Task[:ann_text].invoke
|
596
|
-
File.write ann_text_dst, ann_text
|
597
|
-
end
|
598
|
-
|
599
|
-
CLEAN.include ann_text_dst
|
600
|
-
|
601
|
-
# e-mail
|
602
|
-
ann_mail_dst = 'ANN.eml'
|
603
|
-
|
604
|
-
desc "Build e-mail announcement: #{ann_mail_dst}"
|
605
|
-
task 'ann:mail' => ann_mail_dst
|
606
|
-
|
607
|
-
file ann_mail_dst => doc_man_deps do
|
608
|
-
File.open ann_mail_dst, 'w' do |f|
|
609
|
-
require 'time'
|
610
|
-
f.puts "Date: #{Time.now.rfc822}"
|
611
|
-
|
612
|
-
f.puts 'To: ruby-talk@ruby-lang.org'
|
613
|
-
f.puts 'From: "%s" <%s>' % project_module::AUTHORS.first
|
614
|
-
f.puts "Subject: #{ann_subject}"
|
615
|
-
|
616
|
-
Rake::Task[:ann_text].invoke
|
617
|
-
f.puts '', ann_text
|
618
|
-
end
|
619
|
-
end
|
620
|
-
|
621
|
-
CLEAN.include ann_mail_dst
|
622
|
-
|
623
|
-
# packaging
|
624
|
-
desc 'Build a release.'
|
625
|
-
task :pak => [:clobber, :doc] do
|
626
|
-
sh $0, 'package'
|
627
|
-
end
|
628
|
-
CLEAN.include 'pkg'
|
629
|
-
|
630
|
-
# ruby gem
|
631
|
-
require 'rake/gempackagetask'
|
632
|
-
|
633
|
-
gem = Gem::Specification.new do |gem|
|
634
|
-
authors = project_module::AUTHORS
|
635
|
-
|
636
|
-
if author = authors.first
|
637
|
-
gem.author, gem.email = author
|
638
|
-
end
|
639
|
-
|
640
|
-
if authors.length > 1
|
641
|
-
gem.authors = authors.map {|name, mail| name }
|
642
|
-
end
|
643
|
-
|
644
|
-
gem.rubyforge_project = options[:rubyforge_project]
|
645
|
-
|
646
|
-
# XXX: In theory, `gem.name` should be assigned to
|
647
|
-
# ::PROJECT instead of ::PROGRAM
|
648
|
-
#
|
649
|
-
# In practice, PROJECT may contain non-word
|
650
|
-
# characters and may also contain a mixture
|
651
|
-
# of lowercase and uppercase letters.
|
652
|
-
#
|
653
|
-
# This makes it difficult for people to
|
654
|
-
# install the project gem because they must
|
655
|
-
# remember the exact spelling used in
|
656
|
-
# `gem.name` when running `gem install ____`.
|
657
|
-
#
|
658
|
-
# For example, consider the "RedCloth" gem.
|
659
|
-
#
|
660
|
-
gem.name = project_module::PROGRAM
|
661
|
-
|
662
|
-
gem.version = project_module::VERSION
|
663
|
-
gem.summary = project_module::TAGLINE
|
664
|
-
gem.description = gem.summary
|
665
|
-
gem.homepage = project_module::WEBSITE
|
666
|
-
gem.files = FileList['**/*'].exclude('_darcs') - CLEAN
|
667
|
-
gem.executables = project_module::PROGRAM
|
668
|
-
gem.has_rdoc = true
|
669
|
-
|
670
|
-
unless project_module == Inochi
|
671
|
-
gem.add_dependency 'inochi', Inochi::VERSION.requirement
|
672
|
-
end
|
673
|
-
|
674
|
-
project_module::REQUIRE.each_pair do |gem_name, version_reqs|
|
675
|
-
gem.add_dependency gem_name, *version_reqs
|
676
|
-
end
|
677
|
-
|
678
|
-
# additional configuration is done by user
|
679
|
-
yield gem if gem_config
|
680
|
-
end
|
681
|
-
|
682
|
-
Rake::GemPackageTask.new(gem).define
|
683
|
-
|
684
|
-
# XXX: hide the tasks defined by the above gem packaging library
|
685
|
-
%w[gem package repackage clobber_package].each {|t| hide_rake_task[t] }
|
686
|
-
|
687
|
-
# releasing
|
688
|
-
desc 'Publish a release.'
|
689
|
-
task 'pub' => %w[ pub:pak pub:doc pub:ann ]
|
690
|
-
|
691
|
-
# connect to RubyForge services
|
692
|
-
pub_forge = nil
|
693
|
-
pub_forge_project = options[:rubyforge_project]
|
694
|
-
pub_forge_section = options[:rubyforge_section]
|
695
|
-
|
696
|
-
task :pub_forge do
|
697
|
-
require 'rubyforge'
|
698
|
-
pub_forge = RubyForge.new
|
699
|
-
pub_forge.configure('release_date' => project_module::RELEASE)
|
700
|
-
|
701
|
-
unless pub_forge.autoconfig['group_ids'].key? pub_forge_project
|
702
|
-
raise "The #{pub_forge_project.inspect} project was not recognized by the RubyForge client. Either specify a different RubyForge project by passing the :rubyforge_project option to Inochi.rake(), or ensure that the client is configured correctly (see `rubyforge --help` for help) and try again."
|
703
|
-
end
|
704
|
-
|
705
|
-
pub_forge.login
|
706
|
-
end
|
707
|
-
|
708
|
-
# documentation
|
709
|
-
desc 'Publish documentation to project website.'
|
710
|
-
task 'pub:doc' => [:doc, 'ann:feed'] do
|
711
|
-
target = options[:upload_target]
|
712
|
-
|
713
|
-
unless target
|
714
|
-
require 'addressable/uri'
|
715
|
-
docsite = Addressable::URI.parse(project_module::DOCSITE)
|
716
|
-
|
717
|
-
# provide uploading capability to websites hosted on RubyForge
|
718
|
-
if docsite.host.include? '.rubyforge.org'
|
719
|
-
target = "#{pub_forge.userconfig['username']}@rubyforge.org:#{File.join '/var/www/gforge-projects', options[:rubyforge_project], docsite.path}"
|
720
|
-
end
|
721
|
-
end
|
722
|
-
|
723
|
-
if target
|
724
|
-
cmd = ['rsync', '-auvz', 'doc/', "#{target}/"]
|
725
|
-
cmd.push '--delete' if options[:upload_delete]
|
726
|
-
cmd.concat options[:upload_options]
|
727
|
-
|
728
|
-
p cmd
|
729
|
-
sh(*cmd)
|
730
|
-
end
|
731
|
-
end
|
732
|
-
|
733
|
-
# announcement
|
734
|
-
desc 'Publish all announcements.'
|
735
|
-
task 'pub:ann' => %w[ pub:ann:forge pub:ann:raa pub:ann:talk ]
|
736
|
-
|
737
|
-
# login information
|
738
|
-
ann_logins_file = options[:logins_file]
|
739
|
-
ann_logins = nil
|
740
|
-
|
741
|
-
task :ann_logins do
|
742
|
-
ann_logins = begin
|
743
|
-
require 'yaml'
|
744
|
-
YAML.load_file ann_logins_file
|
745
|
-
rescue => e
|
746
|
-
warn "Could not read login information from #{ann_logins_file.inspect}:"
|
747
|
-
warn e
|
748
|
-
warn "** You will NOT be able to publish release announcements! **"
|
749
|
-
{}
|
750
|
-
end
|
751
|
-
end
|
752
|
-
|
753
|
-
desc 'Announce to RubyForge news.'
|
754
|
-
task 'pub:ann:forge' => :pub_forge do
|
755
|
-
project = options[:rubyforge_project]
|
756
|
-
|
757
|
-
if group_id = pub_forge.autoconfig['group_ids'][project]
|
758
|
-
# check if this release was already announced
|
759
|
-
require 'mechanize'
|
760
|
-
www = WWW::Mechanize.new
|
761
|
-
page = www.get "http://rubyforge.org/news/?group_id=#{group_id}"
|
762
|
-
|
763
|
-
posts = (page/'//a[starts-with(./@href, "/forum/forum.php?forum_id=")]/text()').map {|e| e.to_s.gsub("\302\240", '').strip }
|
764
|
-
|
765
|
-
already_announced = posts.include? ann_subject
|
766
|
-
|
767
|
-
if already_announced
|
768
|
-
warn "This release was already announced to RubyForge news, so I will NOT announce it there again."
|
769
|
-
else
|
770
|
-
# make the announcement
|
771
|
-
Rake::Task[:ann_text].invoke
|
772
|
-
pub_forge.post_news project, ann_subject, ann_text
|
773
|
-
|
774
|
-
puts "Successfully announced to RubyForge news:"
|
775
|
-
puts page.uri
|
776
|
-
end
|
777
|
-
else
|
778
|
-
raise "Could not determine the group_id of the #{project.inspect} RubyForge project. Run `rubyforge config` and try again."
|
779
|
-
end
|
780
|
-
end
|
781
|
-
|
782
|
-
desc 'Announce to ruby-talk mailing list.'
|
783
|
-
task 'pub:ann:talk' => :ann_logins do
|
784
|
-
host = 'http://ruby-forum.com'
|
785
|
-
ruby_talk = 4 # ruby-talk forum ID
|
786
|
-
|
787
|
-
require 'mechanize'
|
788
|
-
www = WWW::Mechanize.new
|
789
|
-
|
790
|
-
# check if this release was already announced
|
791
|
-
already_announced =
|
792
|
-
begin
|
793
|
-
page = www.get "#{host}/forum/#{ruby_talk}", :filter => %{"#{ann_subject}"}
|
794
|
-
|
795
|
-
posts = (page/'//div[@class="forum"]//a[starts-with(./@href, "/topic/")]/text()').map {|e| e.to_s.strip }
|
796
|
-
posts.include? ann_subject
|
797
|
-
rescue
|
798
|
-
false
|
799
|
-
end
|
800
|
-
|
801
|
-
if already_announced
|
802
|
-
warn "This release was already announced to the ruby-talk mailing list, so I will NOT announce it there again."
|
803
|
-
else
|
804
|
-
# log in to RubyForum
|
805
|
-
page = www.get "#{host}/user/login"
|
806
|
-
form = page.forms.first
|
807
|
-
|
808
|
-
if login = ann_logins['www.ruby-forum.com']
|
809
|
-
form['name'] = login['user']
|
810
|
-
form['password'] = login['pass']
|
811
|
-
end
|
812
|
-
|
813
|
-
page = form.click_button # use the first submit button
|
814
|
-
|
815
|
-
if (page/'//a[@href="/user/logout"]').empty?
|
816
|
-
warn "Could not log in to RubyForum using the login information in #{ann_logins_file.inspect}, so I can NOT announce this release to the ruby-talk mailing list."
|
817
|
-
else
|
818
|
-
# make the announcement
|
819
|
-
page = www.get "#{host}/topic/new?forum_id=#{ruby_talk}"
|
820
|
-
form = page.forms.first
|
821
|
-
|
822
|
-
Rake::Task[:ann_text].invoke
|
823
|
-
form['post[subject]'] = ann_subject
|
824
|
-
form['post[text]'] = ann_text
|
825
|
-
|
826
|
-
form.checkboxes.first.check # enable email notification
|
827
|
-
page = form.submit
|
828
|
-
|
829
|
-
errors = [page/'//div[@class="error"]/text()'].flatten
|
830
|
-
if errors.empty?
|
831
|
-
puts "Successfully announced to ruby-talk mailing list:"
|
832
|
-
puts page.uri
|
833
|
-
else
|
834
|
-
warn "Could not announce to ruby-talk mailing list:"
|
835
|
-
warn errors.join("\n")
|
836
|
-
end
|
837
|
-
end
|
838
|
-
end
|
839
|
-
end
|
840
|
-
|
841
|
-
desc 'Announce to RAA (Ruby Application Archive).'
|
842
|
-
task 'pub:ann:raa' => :ann_logins do
|
843
|
-
show_page_error = lambda do |page, message|
|
844
|
-
warn "#{message}, so I can NOT announce this release to RAA:"
|
845
|
-
warn "#{(page/'h2').text} -- #{(page/'p').first.text.strip}"
|
846
|
-
end
|
847
|
-
|
848
|
-
resource = "#{options[:raa_project].inspect} project entry on RAA"
|
849
|
-
|
850
|
-
require 'mechanize'
|
851
|
-
www = WWW::Mechanize.new
|
852
|
-
page = www.get "http://raa.ruby-lang.org/update.rhtml?name=#{options[:raa_project]}"
|
853
|
-
|
854
|
-
if form = page.forms[1]
|
855
|
-
resource << " (owned by #{form.owner.inspect})"
|
856
|
-
|
857
|
-
Rake::Task[:ann_nfo_text].invoke
|
858
|
-
form['description'] = ann_nfo_text
|
859
|
-
form['description_style'] = 'Pre-formatted'
|
860
|
-
form['short_description'] = project_module::TAGLINE
|
861
|
-
form['version'] = project_module::VERSION
|
862
|
-
form['url'] = project_module::WEBSITE
|
863
|
-
form['pass'] = ann_logins['raa.ruby-lang.org']['pass']
|
864
|
-
|
865
|
-
page = form.submit
|
866
|
-
|
867
|
-
if page.title =~ /error/i
|
868
|
-
show_page_error[page, "Could not update #{resource}"]
|
869
|
-
else
|
870
|
-
puts "Successfully announced to RAA (Ruby Application Archive)."
|
871
|
-
end
|
872
|
-
else
|
873
|
-
show_page_error[page, "Could not access #{resource}"]
|
874
|
-
end
|
875
|
-
end
|
876
|
-
|
877
|
-
# release packages
|
878
|
-
desc 'Publish release packages to RubyForge.'
|
879
|
-
task 'pub:pak' => :pub_forge do
|
880
|
-
# check if this release was already published
|
881
|
-
version = project_module::VERSION
|
882
|
-
packages = pub_forge.autoconfig['release_ids'][pub_forge_section]
|
883
|
-
|
884
|
-
if packages and packages.key? version
|
885
|
-
warn "The release packages were already published, so I will NOT publish them again."
|
886
|
-
else
|
887
|
-
# create the FRS package section
|
888
|
-
unless pub_forge.autoconfig['package_ids'].key? pub_forge_section
|
889
|
-
pub_forge.create_package pub_forge_project, pub_forge_section
|
890
|
-
end
|
891
|
-
|
892
|
-
# publish the package to the section
|
893
|
-
uploader = lambda do |command, *files|
|
894
|
-
pub_forge.__send__ command, pub_forge_project, pub_forge_section, version, *files
|
895
|
-
end
|
896
|
-
|
897
|
-
Rake::Task[:pak].invoke
|
898
|
-
packages = Dir['pkg/*.[a-z]*']
|
899
|
-
|
900
|
-
unless packages.empty?
|
901
|
-
# NOTE: use the 'add_release' command ONLY for the first
|
902
|
-
# file because it creates a new sub-section on the
|
903
|
-
# RubyForge download page; we do not want one package
|
904
|
-
# per sub-section on the RubyForge download page!
|
905
|
-
#
|
906
|
-
uploader[:add_release, packages.shift]
|
907
|
-
|
908
|
-
unless packages.empty?
|
909
|
-
uploader[:add_file, *packages]
|
910
|
-
end
|
911
|
-
|
912
|
-
puts "Successfully published release packages to RubyForge."
|
913
|
-
end
|
914
|
-
end
|
915
|
-
end
|
916
|
-
end
|
917
|
-
|
918
|
-
##
|
919
|
-
# Provides a common configuration for the project's user manual:
|
920
|
-
#
|
921
|
-
# * Assigns the title, subtitle, date, and authors for the document.
|
922
|
-
#
|
923
|
-
# You may override these assignments by reassigning these
|
924
|
-
# document parameters AFTER this method is invoked.
|
925
|
-
#
|
926
|
-
# Refer to the "document parameters" for the XHTML
|
927
|
-
# format in the "erbook" user manual for details.
|
928
|
-
#
|
929
|
-
# * Provides the project's configuration as global variables in the document.
|
930
|
-
#
|
931
|
-
# For example, <%= $version %> is the same as
|
932
|
-
# <%= project_module::VERSION %> in the document.
|
933
|
-
#
|
934
|
-
# * Defines a "project_summary" node for use in the document. The body
|
935
|
-
# of this node should contain a brief introduction to the project.
|
936
|
-
#
|
937
|
-
# * Defines a "project_history" node for use in the document. The body
|
938
|
-
# of this node should contain other nodes, each of which represent a
|
939
|
-
# single set of release notes for one of the project's releases.
|
940
|
-
#
|
941
|
-
# It is assumed that this method is called
|
942
|
-
# from within the Inochi.rake() environment.
|
943
|
-
#
|
944
|
-
# @param [Symbol] project_symbol
|
945
|
-
# Name of the Ruby constant which serves
|
946
|
-
# as a namespace for the entire project.
|
947
|
-
#
|
948
|
-
# @param [ERBook::Document::Template] book_template
|
949
|
-
# The eRuby template which serves as the documentation for the project.
|
950
|
-
#
|
951
|
-
def book project_symbol, book_template
|
952
|
-
project_module = fetch_project_module(project_symbol)
|
953
|
-
|
954
|
-
# provide project constants as global variables to the user manual
|
955
|
-
project_module::INOCHI.each_pair do |param, value|
|
956
|
-
eval "$#{param} = value", binding
|
957
|
-
end
|
958
|
-
|
959
|
-
# set document parameters for the user manual
|
960
|
-
$title = project_module::DISPLAY
|
961
|
-
$subtitle = project_module::TAGLINE
|
962
|
-
$feeds = { File.join(project_module::DOCSITE, 'ann.xml') => :rss }
|
963
|
-
$authors = Hash[
|
964
|
-
*project_module::AUTHORS.map do |name, addr|
|
965
|
-
# convert raw e-mail addresses into URLs for the erbook XHTML format
|
966
|
-
addr = "mailto:#{addr}" unless addr =~ /^\w+:/
|
967
|
-
|
968
|
-
[name, addr]
|
969
|
-
end.flatten
|
970
|
-
]
|
971
|
-
|
972
|
-
class << book_template
|
973
|
-
def project_summary
|
974
|
-
raise ArgumentError, 'block must be given' unless block_given?
|
975
|
-
node do
|
976
|
-
$project_summary_node = @nodes.last
|
977
|
-
yield
|
978
|
-
end
|
979
|
-
end
|
980
|
-
|
981
|
-
def project_history
|
982
|
-
raise ArgumentError, 'block must be given' unless block_given?
|
983
|
-
node do
|
984
|
-
$project_history_node = @nodes.last
|
985
|
-
yield
|
986
|
-
end
|
987
|
-
end
|
988
|
-
end
|
989
|
-
end
|
990
|
-
|
991
|
-
##
|
992
|
-
# Returns the name of the main program executable, which
|
993
|
-
# is the same as the project name fully in lowercase.
|
994
|
-
#
|
995
|
-
def calc_program_name project_symbol
|
996
|
-
camel_to_snake_case(project_symbol).downcase
|
997
|
-
end
|
998
|
-
|
999
|
-
##
|
1000
|
-
# Calculates the name of the project module from the given project name.
|
1001
|
-
#
|
1002
|
-
def calc_project_symbol project_name
|
1003
|
-
name = project_name.to_s.gsub(/\W+/, '_').squeeze('_').gsub(/^_|_$/, '')
|
1004
|
-
(name[0,1].upcase + name[1..-1]).to_sym
|
1005
|
-
end
|
1006
|
-
|
1007
|
-
##
|
1008
|
-
# Transforms the given input from CamelCase to snake_case.
|
1009
|
-
#
|
1010
|
-
def camel_to_snake_case input
|
1011
|
-
input = input.to_s.dup
|
1012
|
-
|
1013
|
-
# handle camel case like FooBar => Foo_Bar
|
1014
|
-
while input.gsub!(/([a-z]+)([A-Z])(\w+)/) { $1 + '_' + $2 + $3 }
|
1015
|
-
end
|
1016
|
-
|
1017
|
-
# handle abbreviations like XMLParser => XML_Parser
|
1018
|
-
while input.gsub!(/([A-Z]+)([A-Z])([a-z]+)/) { $1 + '_' + $2 + $3 }
|
1019
|
-
end
|
1020
|
-
|
1021
|
-
input
|
1022
|
-
end
|
1023
|
-
|
1024
|
-
private
|
1025
|
-
|
1026
|
-
##
|
1027
|
-
# Returns the path of the file in which this method was called. Calls
|
1028
|
-
# to this method from within *THIS* file are excluded from the search.
|
1029
|
-
#
|
1030
|
-
def first_caller_file
|
1031
|
-
File.expand_path caller.each {|s| !s.include? __FILE__ and s =~ /^(.*?):\d+/ and break $1 }
|
1032
|
-
end
|
1033
|
-
|
1034
|
-
##
|
1035
|
-
# Returns the project module corresponding to the given symbol.
|
1036
|
-
# A new module is created if none already exists.
|
1037
|
-
#
|
1038
|
-
def fetch_project_module project_symbol
|
1039
|
-
if Object.const_defined? project_symbol
|
1040
|
-
project_module = Object.const_get(project_symbol)
|
1041
|
-
else
|
1042
|
-
project_module = Module.new
|
1043
|
-
Object.const_set project_symbol, project_module
|
1044
|
-
end
|
1045
|
-
|
1046
|
-
project_module
|
1047
|
-
end
|
1048
|
-
end
|
1049
|
-
end
|
1050
|
-
|
1051
|
-
##
|
1052
|
-
# utility methods
|
1053
|
-
#
|
1054
|
-
|
1055
|
-
unless File.respond_to? :write
|
1056
|
-
##
|
1057
|
-
# Writes the given content to the given file.
|
1058
|
-
#
|
1059
|
-
# @return number of bytes written
|
1060
|
-
#
|
1061
|
-
def File.write path, content
|
1062
|
-
File.open(path, 'wb') {|f| f.write content.to_s }
|
1063
|
-
end
|
1064
|
-
end
|