inochi 1.1.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CREDITS +17 -1
- data/bin/inochi +19 -539
- data/lib/inochi.rb +1 -41
- data/lib/inochi/engine.rb +101 -0
- data/lib/inochi/generate.rb +52 -0
- data/lib/inochi/inochi.rb +109 -0
- data/lib/inochi/tasks/ann.rake +230 -0
- data/lib/inochi/tasks/api.rake +28 -0
- data/lib/inochi/tasks/gem.rake +46 -0
- data/lib/inochi/tasks/init.rake +38 -0
- data/lib/inochi/tasks/man.rake +78 -0
- data/lib/inochi/tasks/project.rake +25 -0
- data/lib/inochi/tasks/pub.rake +130 -0
- data/lib/inochi/templates/CREDITS.rbs +18 -0
- data/lib/inochi/templates/EXAMPLES.rbs +24 -0
- data/lib/inochi/templates/FURTHER.rbs +17 -0
- data/lib/inochi/templates/HACKING.rbs +92 -0
- data/lib/inochi/templates/HISTORY.rbs +55 -0
- data/lib/inochi/templates/LICENSE.rbs +15 -0
- data/lib/inochi/templates/MANUAL.rbs +27 -0
- data/lib/inochi/templates/README.rbs +60 -0
- data/lib/inochi/templates/USAGE.rbs +23 -0
- data/lib/inochi/templates/command.rbs +23 -0
- data/lib/inochi/templates/inochi.opts.rbs +43 -0
- data/lib/inochi/templates/inochi.rb.rbs +102 -0
- data/lib/inochi/templates/library.rbs +7 -0
- data/lib/inochi/templates/library_test.rb.rbs +3 -0
- data/lib/inochi/templates/test_helper.rb.rbs +3 -0
- data/lib/inochi/templates/test_runner.rbs +25 -0
- data/{doc → logo}/inochi.png +0 -0
- data/man.html +959 -0
- data/man/man1/inochi.1.gz +0 -0
- metadata +129 -198
- data/doc/README +0 -6
- data/doc/api/apple-touch-icon.png +0 -0
- data/doc/api/classes/Array.html +0 -370
- data/doc/api/classes/File.html +0 -110
- data/doc/api/classes/Inochi.html +0 -1477
- data/doc/api/classes/Inochi/Manual.html +0 -157
- data/doc/api/classes/Inochi/Phrases.html +0 -331
- data/doc/api/classes/Inochi/Version.html +0 -190
- data/doc/api/classes/TempDir.html +0 -164
- data/doc/api/created.rid +0 -1
- data/doc/api/css/main.css +0 -263
- data/doc/api/css/panel.css +0 -383
- data/doc/api/css/reset.css +0 -53
- data/doc/api/favicon.ico +0 -0
- data/doc/api/files/CREDITS.html +0 -61
- data/doc/api/files/LICENSE.html +0 -76
- data/doc/api/files/lib/inochi/book_rb.html +0 -106
- data/doc/api/files/lib/inochi/init_rb.html +0 -66
- data/doc/api/files/lib/inochi/main_rb.html +0 -52
- data/doc/api/files/lib/inochi/rake_rb.html +0 -52
- data/doc/api/files/lib/inochi/test/bacon_rb.html +0 -67
- data/doc/api/files/lib/inochi/test/context_rb.html +0 -69
- data/doc/api/files/lib/inochi/test/dfect_rb.html +0 -67
- data/doc/api/files/lib/inochi/test/matchy_rb.html +0 -69
- data/doc/api/files/lib/inochi/test/minitest_rb.html +0 -71
- data/doc/api/files/lib/inochi/test/mocha_rb.html +0 -67
- data/doc/api/files/lib/inochi/test/rspec_rb.html +0 -67
- data/doc/api/files/lib/inochi/test/shoulda_rb.html +0 -67
- data/doc/api/files/lib/inochi/test/test_spec_rb.html +0 -67
- data/doc/api/files/lib/inochi/test/test_unit_rb.html +0 -67
- data/doc/api/files/lib/inochi/util/combo_rb.html +0 -59
- data/doc/api/files/lib/inochi/util/tempdir_rb.html +0 -68
- data/doc/api/files/lib/inochi/util_rb.html +0 -59
- data/doc/api/files/lib/inochi_rb.html +0 -76
- data/doc/api/i/arrows.png +0 -0
- data/doc/api/i/results_bg.png +0 -0
- data/doc/api/i/tree_bg.png +0 -0
- data/doc/api/index.html +0 -14
- data/doc/api/js/jquery-1.3.2.min.js +0 -19
- data/doc/api/js/jquery-effect.js +0 -593
- data/doc/api/js/main.js +0 -22
- data/doc/api/js/searchdoc.js +0 -628
- data/doc/api/panel/index.html +0 -71
- data/doc/api/panel/search_index.js +0 -1
- data/doc/api/panel/tree.js +0 -1
- data/doc/history.erb +0 -268
- data/doc/index.erb +0 -11
- data/doc/index.html +0 -3179
- data/doc/inochi.svg +0 -405
- data/doc/intro.erb +0 -87
- data/doc/setup.erb +0 -105
- data/doc/usage.erb +0 -641
- data/lib/inochi/book.rb +0 -91
- data/lib/inochi/init.rb +0 -256
- data/lib/inochi/main.rb +0 -85
- data/lib/inochi/rake.rb +0 -902
- data/lib/inochi/test/bacon.rb +0 -3
- data/lib/inochi/test/context.rb +0 -4
- data/lib/inochi/test/dfect.rb +0 -3
- data/lib/inochi/test/matchy.rb +0 -4
- data/lib/inochi/test/minitest.rb +0 -7
- data/lib/inochi/test/mocha.rb +0 -3
- data/lib/inochi/test/rspec.rb +0 -3
- data/lib/inochi/test/shoulda.rb +0 -3
- data/lib/inochi/test/test_spec.rb +0 -3
- data/lib/inochi/test/test_unit.rb +0 -3
- data/lib/inochi/util.rb +0 -99
- data/lib/inochi/util/combo.rb +0 -191
- data/lib/inochi/util/tempdir.rb +0 -29
- data/rakefile +0 -12
- data/test/inochi.rb +0 -111
data/lib/inochi.rb
CHANGED
@@ -1,41 +1 @@
|
|
1
|
-
|
2
|
-
# Copyright protects this work.
|
3
|
-
# See LICENSE file for details.
|
4
|
-
#++
|
5
|
-
|
6
|
-
require 'rubygems'
|
7
|
-
|
8
|
-
module Inochi
|
9
|
-
libs = File.dirname(__FILE__)
|
10
|
-
$LOAD_PATH << libs unless $LOAD_PATH.include? libs
|
11
|
-
end
|
12
|
-
|
13
|
-
require 'inochi/init'
|
14
|
-
require 'inochi/main'
|
15
|
-
require 'inochi/rake'
|
16
|
-
require 'inochi/book'
|
17
|
-
require 'inochi/util'
|
18
|
-
|
19
|
-
Inochi.init :Inochi,
|
20
|
-
:version => '1.1.1',
|
21
|
-
:release => '2009-10-03',
|
22
|
-
:website => 'http://snk.tuxfamily.org/lib/inochi/',
|
23
|
-
:tagline => 'Gives life to RubyGems-based software',
|
24
|
-
:require => {
|
25
|
-
'trollop' => '~> 1', # for parsing command-line
|
26
|
-
'launchy' => ['~> 0', '>= 0.3.3'], # for launching a browser
|
27
|
-
},
|
28
|
-
:develop => {
|
29
|
-
'rake' => ['~> 0', '>= 0.8.4'],
|
30
|
-
'rubyforge' => '~> 2', # for publishing gems
|
31
|
-
'mechanize' => '~> 0', # for web automation
|
32
|
-
'voloko-sdoc' => ['~> 0', '>= 0.2.10'], # for API docs
|
33
|
-
'addressable' => '~> 2', # for parsing URIs properly
|
34
|
-
'erbook' => '~> 7', # for generating user manual
|
35
|
-
'babelfish' => '~> 0', # for language translation
|
36
|
-
'relevance-rcov' => nil, # for code coverage statistics
|
37
|
-
'flay' => nil, # for code quality analysis
|
38
|
-
'reek' => nil, # for code quality analysis
|
39
|
-
'roodi' => nil, # for code quality analysis
|
40
|
-
'ZenTest' => '~> 4', # for the `multiruby` tool
|
41
|
-
}
|
1
|
+
require 'inochi/inochi'
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'time'
|
3
|
+
require 'rake'
|
4
|
+
require 'rake/clean'
|
5
|
+
require 'shellwords'
|
6
|
+
|
7
|
+
module Inochi
|
8
|
+
class Engine
|
9
|
+
|
10
|
+
require 'inochi/generate'
|
11
|
+
include Inochi::Generate
|
12
|
+
|
13
|
+
def run
|
14
|
+
register_rake_tasks
|
15
|
+
run_rake_tasks
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# Renders the given RBS (ruby string) file
|
20
|
+
# and/or template inside the given binding.
|
21
|
+
#
|
22
|
+
def self.render_rbs binding, filename, template = File.read(filename)
|
23
|
+
here = "TEMPORARY_HERE_DOC#{object_id}TEMPORARY_HERE_DOC"
|
24
|
+
eval("<<#{here}\n#{template}\n#{here}", binding, filename).chomp
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def run_rake_tasks
|
30
|
+
task :default do
|
31
|
+
Rake.application.options.show_task_pattern = //
|
32
|
+
Rake.application.display_tasks_and_comments
|
33
|
+
end
|
34
|
+
|
35
|
+
Rake.application.init 'inochi'
|
36
|
+
Rake.application.top_level
|
37
|
+
end
|
38
|
+
|
39
|
+
def register_rake_tasks
|
40
|
+
Dir[File.dirname(__FILE__) + '/tasks/*.rake'].each do |file|
|
41
|
+
instance_eval File.read(file), file
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
TEMPLATE_DIR = File.join(File.dirname(__FILE__), 'templates')
|
46
|
+
|
47
|
+
##
|
48
|
+
# Renders the given RBS template file (found in the
|
49
|
+
# TEMPLATE_DIR directory) to the given output file.
|
50
|
+
#
|
51
|
+
def create_from_rbs binding, output_file, template_file = File.basename(output_file)
|
52
|
+
actual_template_file = "#{TEMPLATE_DIR}/#{template_file}.rbs"
|
53
|
+
create output_file, self.class.render_rbs(binding, actual_template_file)
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Writes the given contents to the file at the given
|
58
|
+
# path. If the given path already exists, then a
|
59
|
+
# backup is created before invoking the merging tool.
|
60
|
+
#
|
61
|
+
def create path, body, merger = ENV[:merger]
|
62
|
+
generate path, body do |*files|
|
63
|
+
system "#{merger} #{Shellwords.join files}" if merger
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Returns the name of the main program executable, which
|
69
|
+
# is the same as the project name fully in lowercase.
|
70
|
+
#
|
71
|
+
def self.calc_package_name library_name
|
72
|
+
camel_to_snake_case(library_name).downcase
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# Calculates the name of the project module from the given project name.
|
77
|
+
#
|
78
|
+
def self.calc_library_name project_name
|
79
|
+
name = project_name.to_s.gsub(/\W+/, '_').squeeze('_').gsub(/^_|_$/, '')
|
80
|
+
(name[0,1].upcase + name[1..-1]).to_sym
|
81
|
+
end
|
82
|
+
|
83
|
+
##
|
84
|
+
# Transforms the given input from CamelCase to snake_case.
|
85
|
+
#
|
86
|
+
def self.camel_to_snake_case input
|
87
|
+
input = input.to_s.dup
|
88
|
+
|
89
|
+
# handle camel case like FooBar => Foo_Bar
|
90
|
+
while input.gsub!(/([a-z]+)([A-Z])(\w+)/) { $1 + '_' + $2 + $3 }
|
91
|
+
end
|
92
|
+
|
93
|
+
# handle abbreviations like XMLParser => XML_Parser
|
94
|
+
while input.gsub!(/([A-Z]+)([A-Z])([a-z]+)/) { $1 + '_' + $2 + $3 }
|
95
|
+
end
|
96
|
+
|
97
|
+
input
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'digest/sha1'
|
3
|
+
|
4
|
+
module Inochi
|
5
|
+
module Generate
|
6
|
+
extend self
|
7
|
+
|
8
|
+
##
|
9
|
+
# Notify the user about some action being performed.
|
10
|
+
#
|
11
|
+
def notify action, message
|
12
|
+
printf "%16s %s\n", action, message
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# Writes the given contents to the file at the given
|
17
|
+
# path. If the given path already exists, then a
|
18
|
+
# backup is created before invoking the given block.
|
19
|
+
#
|
20
|
+
def generate path, content # :yields: old_file, new_file, output_file
|
21
|
+
if File.exist? path
|
22
|
+
old_digest = Digest::SHA1.digest(File.read(path))
|
23
|
+
new_digest = Digest::SHA1.digest(content)
|
24
|
+
|
25
|
+
if old_digest == new_digest
|
26
|
+
notify :skip, path
|
27
|
+
else
|
28
|
+
notify :update, path
|
29
|
+
cur, old, new = path, "#{path}.old", "#{path}.new"
|
30
|
+
|
31
|
+
FileUtils.cp cur, old, :preserve => true
|
32
|
+
File.write new, content
|
33
|
+
|
34
|
+
yield old, new, cur if block_given?
|
35
|
+
end
|
36
|
+
else
|
37
|
+
notify :create, path
|
38
|
+
FileUtils.mkdir_p File.dirname(path)
|
39
|
+
File.write path, content
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
unless File.respond_to? :write
|
46
|
+
##
|
47
|
+
# Writes the given content to the given file.
|
48
|
+
#
|
49
|
+
def File.write path, content
|
50
|
+
open(path, 'wb') {|f| f.write content }
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Inochi
|
2
|
+
|
3
|
+
##
|
4
|
+
# Official name of this project.
|
5
|
+
#
|
6
|
+
PROJECT = 'Inochi'
|
7
|
+
|
8
|
+
##
|
9
|
+
# Short single-line description of this project.
|
10
|
+
#
|
11
|
+
TAGLINE = 'Gives life to Ruby projects'
|
12
|
+
|
13
|
+
##
|
14
|
+
# Address of this project's official home page.
|
15
|
+
#
|
16
|
+
WEBSITE = 'http://snk.tuxfamily.org/lib/inochi/'
|
17
|
+
|
18
|
+
##
|
19
|
+
# Number of this release of this project.
|
20
|
+
#
|
21
|
+
VERSION = '2.0.0'
|
22
|
+
|
23
|
+
##
|
24
|
+
# Date of this release of this project.
|
25
|
+
#
|
26
|
+
RELDATE = '2010-04-24'
|
27
|
+
|
28
|
+
##
|
29
|
+
# Description of this release of this project.
|
30
|
+
#
|
31
|
+
def self.inspect
|
32
|
+
"#{PROJECT} #{VERSION} (#{RELDATE})"
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Location of this release of this project.
|
37
|
+
#
|
38
|
+
INSTDIR = File.expand_path('../../..', __FILE__)
|
39
|
+
|
40
|
+
##
|
41
|
+
# RubyGems required by this project during runtime.
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
#
|
45
|
+
# RUNTIME = {
|
46
|
+
# # this project needs exactly version 1.2.3 of the "an_example" gem
|
47
|
+
# "an_example" => [ "1.2.3" ],
|
48
|
+
#
|
49
|
+
# # this project needs at least version 1.2 (but not
|
50
|
+
# # version 1.2.4 or newer) of the "another_example" gem
|
51
|
+
# "another_example" => [ ">= 1.2" , "< 1.2.4" ],
|
52
|
+
#
|
53
|
+
# # this project needs any version of the "yet_another_example" gem
|
54
|
+
# "yet_another_example" => [],
|
55
|
+
# }
|
56
|
+
#
|
57
|
+
RUNTIME = {
|
58
|
+
'highline' => [ '>= 1.5' , '< 2' ], # for echoless password entry
|
59
|
+
'mechanize' => [ '~> 1' ], # for publishing announcements
|
60
|
+
'nokogiri' => [ '>= 1.4' , '< 2' ], # for parsing HTML and XML
|
61
|
+
'rake' => [ '>= 0.8.4' , '< 1' ], # for Inochi::Engine
|
62
|
+
'ronn' => [ '>= 0.5' , '< 1' ], # for making UNIX man pages
|
63
|
+
'yard' => [ ], # for making API documentation
|
64
|
+
}
|
65
|
+
|
66
|
+
##
|
67
|
+
# RubyGems required by this project during development.
|
68
|
+
#
|
69
|
+
# @example
|
70
|
+
#
|
71
|
+
# DEVTIME = {
|
72
|
+
# # this project needs exactly version 1.2.3 of the "an_example" gem
|
73
|
+
# "an_example" => [ "1.2.3" ],
|
74
|
+
#
|
75
|
+
# # this project needs at least version 1.2 (but not
|
76
|
+
# # version 1.2.4 or newer) of the "another_example" gem
|
77
|
+
# "another_example" => [ ">= 1.2" , "< 1.2.4" ],
|
78
|
+
#
|
79
|
+
# # this project needs any version of the "yet_another_example" gem
|
80
|
+
# "yet_another_example" => [],
|
81
|
+
# }
|
82
|
+
#
|
83
|
+
DEVTIME = {
|
84
|
+
'dfect' => [ '>= 1.1.0', '< 2' ], # for unit testing
|
85
|
+
}
|
86
|
+
|
87
|
+
##
|
88
|
+
# Loads the correct version (as defined by the {RUNTIME} or {DEVTIME}
|
89
|
+
# constant in this module) of the given gem or the gem that contains
|
90
|
+
# the given library.
|
91
|
+
#
|
92
|
+
def self.require gem_name_or_library
|
93
|
+
# prepare the correct version of the gem for loading
|
94
|
+
if respond_to? :gem
|
95
|
+
gem_name = gem_name_or_library.to_s.sub(%r{/.*$}, '')
|
96
|
+
if gem_version = RUNTIME[gem_name] || DEVTIME[gem_name]
|
97
|
+
begin
|
98
|
+
gem gem_name, *gem_version
|
99
|
+
rescue LoadError => error
|
100
|
+
warn "#{self.inspect}: #{error}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# do the loading
|
106
|
+
super
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
@@ -0,0 +1,230 @@
|
|
1
|
+
desc 'Build all release announcements.'
|
2
|
+
task :ann => %w[ ann:html ann:text ann:feed ]
|
3
|
+
|
4
|
+
# it has long been a tradition to use an "[ANN]" prefix
|
5
|
+
# when announcing things on the ruby-talk mailing list
|
6
|
+
@ann_subject_prefix = '[ANN] '
|
7
|
+
|
8
|
+
task :@ann_subject do
|
9
|
+
unless @ann_subject
|
10
|
+
Rake::Task[:@project].invoke
|
11
|
+
@ann_subject = @ann_subject_prefix +
|
12
|
+
@project_module::PROJECT + ' ' + @project_module::VERSION
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# fetch project description from manual
|
17
|
+
task :@ann_nfo_html_nodes do
|
18
|
+
unless @ann_nfo_html_nodes
|
19
|
+
begin
|
20
|
+
head, body = fetch_nodes_between('h2#ABOUT', 'h1,h2,h3,h4,h5,h6')
|
21
|
+
rescue => error
|
22
|
+
error.message.insert 0,
|
23
|
+
"The manual lacks a <H2> ABOUT heading.\n"
|
24
|
+
raise error
|
25
|
+
end
|
26
|
+
|
27
|
+
@ann_nfo_html_nodes = body
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
task :@ann_nfo_text do
|
32
|
+
unless @ann_nfo_text
|
33
|
+
Rake::Task[:@ann_nfo_html_nodes].invoke
|
34
|
+
@ann_nfo_text = nodes_inner_text(@ann_nfo_html_nodes)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# fetch release notes from manual
|
39
|
+
task :@ann_rel_html_body_nodes do
|
40
|
+
unless @ann_rel_html_body_nodes
|
41
|
+
begin
|
42
|
+
head, body = fetch_nodes_between('h2#VERSIONS ~ h3', 'h1,h2,h3')
|
43
|
+
rescue => error
|
44
|
+
error.message.insert 0,
|
45
|
+
"The manual lacks a <H3> heading under a <H2> VERSIONS heading.\n"
|
46
|
+
raise error
|
47
|
+
end
|
48
|
+
|
49
|
+
@ann_rel_html_title_node = head
|
50
|
+
@ann_rel_html_body_nodes = body
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# fetch authors list from manual
|
55
|
+
task :@project_authors_html_nodes do
|
56
|
+
unless @project_authors_html_nodes
|
57
|
+
begin
|
58
|
+
head, body = fetch_nodes_between('h2#AUTHORS,h2#CREDITS',
|
59
|
+
'h1,h2,h3,h4,h5,h6')
|
60
|
+
rescue => error
|
61
|
+
error.message.insert 0,
|
62
|
+
"The manual lacks content under a <H2> AUTHORS or CREDITS heading.\n"
|
63
|
+
raise error
|
64
|
+
end
|
65
|
+
|
66
|
+
@project_authors_html_nodes = body
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
task :@project_authors_text do
|
71
|
+
unless @project_authors_text
|
72
|
+
Rake::Task[:@project_authors_html_nodes].invoke
|
73
|
+
@project_authors_text = nodes_inner_text(@project_authors_html_nodes)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# build release announcement
|
78
|
+
task :@ann_html do
|
79
|
+
unless @ann_html
|
80
|
+
Rake::Task[:@ann_nfo_html_nodes].invoke
|
81
|
+
Rake::Task[:@ann_rel_html_body_nodes].invoke
|
82
|
+
|
83
|
+
@ann_html = %{
|
84
|
+
<center>
|
85
|
+
<h1>#{@project_module::PROJECT}</h1>
|
86
|
+
<h2>#{@project_module::TAGLINE}</h2>
|
87
|
+
<p>#{@project_module::WEBSITE}</p>
|
88
|
+
</center>
|
89
|
+
#{@ann_nfo_html_nodes.join}
|
90
|
+
#{@ann_rel_html_body_nodes.join}
|
91
|
+
}.strip
|
92
|
+
|
93
|
+
@ann_html = resolve_html_links(@ann_html)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
task :@ann_text do
|
98
|
+
unless @ann_text
|
99
|
+
Rake::Task[:@ann_html].invoke
|
100
|
+
@ann_text = convert_html_to_text(@ann_html)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
#-----------------------------------------------------------------------------
|
105
|
+
# HTML
|
106
|
+
#-----------------------------------------------------------------------------
|
107
|
+
|
108
|
+
@ann_html_dst = 'ann.html'
|
109
|
+
|
110
|
+
desc 'Build HTML announcement.'
|
111
|
+
task 'ann:html' => @ann_html_dst
|
112
|
+
|
113
|
+
file @ann_html_dst => @man_src do
|
114
|
+
Rake::Task[:@ann_html].invoke
|
115
|
+
File.write @ann_html_dst, @ann_html
|
116
|
+
end
|
117
|
+
|
118
|
+
CLOBBER.include @ann_html_dst
|
119
|
+
|
120
|
+
#-----------------------------------------------------------------------------
|
121
|
+
# plain text
|
122
|
+
#-----------------------------------------------------------------------------
|
123
|
+
|
124
|
+
@ann_text_dst = 'ann.txt'
|
125
|
+
|
126
|
+
desc 'Build plain text announcement.'
|
127
|
+
task 'ann:text' => @ann_text_dst
|
128
|
+
|
129
|
+
file @ann_text_dst => @man_src do
|
130
|
+
Rake::Task[:@ann_text].invoke
|
131
|
+
File.write @ann_text_dst, @ann_text
|
132
|
+
end
|
133
|
+
|
134
|
+
CLOBBER.include @ann_text_dst
|
135
|
+
|
136
|
+
#-----------------------------------------------------------------------------
|
137
|
+
# RSS feed
|
138
|
+
#-----------------------------------------------------------------------------
|
139
|
+
|
140
|
+
@ann_feed_dst = 'ann.xml'
|
141
|
+
|
142
|
+
desc 'Build RSS feed announcement.'
|
143
|
+
task 'ann:feed' => @ann_feed_dst
|
144
|
+
|
145
|
+
file @ann_feed_dst => @man_src do
|
146
|
+
Rake::Task[:@project].invoke
|
147
|
+
Rake::Task[:@ann_nfo_html_nodes].invoke
|
148
|
+
Rake::Task[:@ann_rel_html_body_nodes].invoke
|
149
|
+
|
150
|
+
require 'rss/maker'
|
151
|
+
rss = RSS::Maker.make('2.0') do |feed|
|
152
|
+
feed.channel.title = @ann_subject_prefix + @project_module::PROJECT
|
153
|
+
feed.channel.link = @project_module::WEBSITE
|
154
|
+
feed.channel.description = @ann_nfo_html_nodes.join
|
155
|
+
|
156
|
+
item = feed.items.new_item
|
157
|
+
item.link = @project_module::WEBSITE
|
158
|
+
require 'time'
|
159
|
+
item.date = Time.parse(@project_module::RELDATE)
|
160
|
+
item.title = @ann_rel_html_title_node.inner_text
|
161
|
+
item.description = @ann_rel_html_body_nodes.join
|
162
|
+
end
|
163
|
+
|
164
|
+
File.write @ann_feed_dst, rss
|
165
|
+
end
|
166
|
+
|
167
|
+
CLOBBER.include @ann_feed_dst
|
168
|
+
|
169
|
+
#-----------------------------------------------------------------------------
|
170
|
+
# helper logic
|
171
|
+
#-----------------------------------------------------------------------------
|
172
|
+
|
173
|
+
def nodes_inner_text nodes
|
174
|
+
nodes.map {|n| n.inner_text }.join(' ').gsub(/\n/, ' ').squeeze(' ').strip
|
175
|
+
end
|
176
|
+
|
177
|
+
##
|
178
|
+
# Fetches all nodes between those matching the given head and tail selectors.
|
179
|
+
#
|
180
|
+
def fetch_nodes_between head_selector, tail_selector
|
181
|
+
Rake::Task[:@man_html_dom].invoke
|
182
|
+
|
183
|
+
head = @man_html_dom.at(head_selector)
|
184
|
+
body = []
|
185
|
+
|
186
|
+
tail = head
|
187
|
+
while tail = tail.next_sibling and not tail.matches? tail_selector
|
188
|
+
body << tail
|
189
|
+
end
|
190
|
+
|
191
|
+
[head, body, tail]
|
192
|
+
end
|
193
|
+
|
194
|
+
##
|
195
|
+
# Converts the given HTML into plain text. we do this using
|
196
|
+
# lynx because (1) it outputs a list of all hyperlinks used
|
197
|
+
# in the HTML document and (2) it runs on all major platforms
|
198
|
+
#
|
199
|
+
def convert_html_to_text html
|
200
|
+
# lynx's -dump option requires a .html file
|
201
|
+
require 'tempfile'
|
202
|
+
tmp_file = Tempfile.new($$).path + '.html'
|
203
|
+
|
204
|
+
begin
|
205
|
+
File.write tmp_file, html
|
206
|
+
|
207
|
+
`lynx -dump #{tmp_file} -width 70`.
|
208
|
+
#
|
209
|
+
# improve readability of list items
|
210
|
+
# by adding a blank line between them
|
211
|
+
#
|
212
|
+
gsub(/(\r?\n)( +\* \S)/, '\1\1\2')
|
213
|
+
ensure
|
214
|
+
File.delete tmp_file
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
##
|
219
|
+
# Converts relative URLs in the given HTML into
|
220
|
+
# absolute URLs bound to the given base URL.
|
221
|
+
#
|
222
|
+
# http://en.wikipedia.org/wiki/URI_scheme#Generic_syntax
|
223
|
+
#
|
224
|
+
def resolve_html_links html, base_url = nil
|
225
|
+
Rake::Task[:@project].invoke
|
226
|
+
base_url ||= @project_module::WEBSITE
|
227
|
+
|
228
|
+
require 'cgi'
|
229
|
+
"<base href='#{CGI.escapeHTML base_url}'/> #{html}"
|
230
|
+
end
|