inochi 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|