ratch 0.1
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.txt +344 -0
- data/README.txt +10 -0
- data/bin/lt +4 -0
- data/bin/ludo +4 -0
- data/bin/ratch +8 -0
- data/data/mint/ratch/announce +224 -0
- data/data/mint/ratch/install +49 -0
- data/data/mint/ratch/notes +183 -0
- data/data/mint/ratch/publish +44 -0
- data/data/mint/ratch/rdoc +40 -0
- data/data/mint/ratch/setup +1616 -0
- data/data/mint/ratch/stats +138 -0
- data/demo/README +8 -0
- data/demo/doc/rdoc/created.rid +1 -0
- data/demo/doc/rdoc/files/README.html +112 -0
- data/demo/doc/rdoc/files/lib/foo/foo_rb.html +145 -0
- data/demo/doc/rdoc/fr_class_index.html +26 -0
- data/demo/doc/rdoc/fr_file_index.html +28 -0
- data/demo/doc/rdoc/fr_method_index.html +27 -0
- data/demo/doc/rdoc/index.html +24 -0
- data/demo/doc/rdoc/rdoc-style.css +208 -0
- data/demo/lib/foo/foo.rb +7 -0
- data/demo/util/conf/rdoc +4 -0
- data/demo/util/one +6 -0
- data/demo/util/rdoc +39 -0
- data/demo/util/tryme +10 -0
- data/dev/taskable-simple.rb +42 -0
- data/dev/taskable.rb +573 -0
- data/lib/ratch/batch.rb +43 -0
- data/lib/ratch/cli/lt.rb +56 -0
- data/lib/ratch/cli/ludo.rb +14 -0
- data/lib/ratch/cli/ratch.rb +47 -0
- data/lib/ratch/configutils.rb +100 -0
- data/lib/ratch/consoleutils.rb +88 -0
- data/lib/ratch/emailutils.rb +88 -0
- data/lib/ratch/fileutils.rb +173 -0
- data/lib/ratch/options.rb +57 -0
- data/lib/ratch/runnable.rb +117 -0
- data/lib/ratch/taskable.rb +105 -0
- data/lib/ratch/taskutils.rb +44 -0
- data/lib/ratch/uploadutils.rb +413 -0
- data/meta/manifest.txt +70 -0
- data/meta/project.yaml +24 -0
- data/misc/original.rb +308 -0
- data/task/setup +1616 -0
- data/task/stats +138 -0
- metadata +114 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
3
|
+
<!DOCTYPE html
|
4
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
5
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
6
|
+
|
7
|
+
<!--
|
8
|
+
|
9
|
+
Methods
|
10
|
+
|
11
|
+
-->
|
12
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
13
|
+
<head>
|
14
|
+
<title>Methods</title>
|
15
|
+
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
16
|
+
<link rel="stylesheet" href="rdoc-style.css" type="text/css" />
|
17
|
+
<base target="docwin" />
|
18
|
+
</head>
|
19
|
+
<body>
|
20
|
+
<div id="index">
|
21
|
+
<h1 class="section-bar">Methods</h1>
|
22
|
+
<div id="index-entries">
|
23
|
+
<a href="files/lib/foo/foo_rb.html#M000001">hello (lib/foo/foo.rb)</a><br />
|
24
|
+
</div>
|
25
|
+
</div>
|
26
|
+
</body>
|
27
|
+
</html>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
2
|
+
<!DOCTYPE html
|
3
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
|
4
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
|
5
|
+
|
6
|
+
<!--
|
7
|
+
|
8
|
+
Foo
|
9
|
+
|
10
|
+
-->
|
11
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
12
|
+
<head>
|
13
|
+
<title>Foo</title>
|
14
|
+
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
15
|
+
</head>
|
16
|
+
<frameset rows="20%, 80%">
|
17
|
+
<frameset cols="25%,35%,45%">
|
18
|
+
<frame src="fr_file_index.html" title="Files" name="Files" />
|
19
|
+
<frame src="fr_class_index.html" name="Classes" />
|
20
|
+
<frame src="fr_method_index.html" name="Methods" />
|
21
|
+
</frameset>
|
22
|
+
<frame src="files/README.html" name="docwin" />
|
23
|
+
</frameset>
|
24
|
+
</html>
|
@@ -0,0 +1,208 @@
|
|
1
|
+
|
2
|
+
body {
|
3
|
+
font-family: Verdana,Arial,Helvetica,sans-serif;
|
4
|
+
font-size: 90%;
|
5
|
+
margin: 0;
|
6
|
+
margin-left: 40px;
|
7
|
+
padding: 0;
|
8
|
+
background: white;
|
9
|
+
}
|
10
|
+
|
11
|
+
h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
|
12
|
+
h1 { font-size: 150%; }
|
13
|
+
h2,h3,h4 { margin-top: 1em; }
|
14
|
+
|
15
|
+
a { background: #eef; color: #039; text-decoration: none; }
|
16
|
+
a:hover { background: #039; color: #eef; }
|
17
|
+
|
18
|
+
/* Override the base stylesheet's Anchor inside a table cell */
|
19
|
+
td > a {
|
20
|
+
background: transparent;
|
21
|
+
color: #039;
|
22
|
+
text-decoration: none;
|
23
|
+
}
|
24
|
+
|
25
|
+
/* and inside a section title */
|
26
|
+
.section-title > a {
|
27
|
+
background: transparent;
|
28
|
+
color: #eee;
|
29
|
+
text-decoration: none;
|
30
|
+
}
|
31
|
+
|
32
|
+
/* === Structural elements =================================== */
|
33
|
+
|
34
|
+
div#index {
|
35
|
+
margin: 0;
|
36
|
+
margin-left: -40px;
|
37
|
+
padding: 0;
|
38
|
+
font-size: 90%;
|
39
|
+
}
|
40
|
+
|
41
|
+
|
42
|
+
div#index a {
|
43
|
+
margin-left: 0.7em;
|
44
|
+
}
|
45
|
+
|
46
|
+
div#index .section-bar {
|
47
|
+
margin-left: 0px;
|
48
|
+
padding-left: 0.7em;
|
49
|
+
background: #ccc;
|
50
|
+
font-size: small;
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
div#classHeader, div#fileHeader {
|
55
|
+
width: auto;
|
56
|
+
color: white;
|
57
|
+
padding: 0.5em 1.5em 0.5em 1.5em;
|
58
|
+
margin: 0;
|
59
|
+
margin-left: -40px;
|
60
|
+
border-bottom: 3px solid #006;
|
61
|
+
}
|
62
|
+
|
63
|
+
div#classHeader a, div#fileHeader a {
|
64
|
+
background: inherit;
|
65
|
+
color: white;
|
66
|
+
}
|
67
|
+
|
68
|
+
div#classHeader td, div#fileHeader td {
|
69
|
+
background: inherit;
|
70
|
+
color: white;
|
71
|
+
}
|
72
|
+
|
73
|
+
|
74
|
+
div#fileHeader {
|
75
|
+
background: #057;
|
76
|
+
}
|
77
|
+
|
78
|
+
div#classHeader {
|
79
|
+
background: #048;
|
80
|
+
}
|
81
|
+
|
82
|
+
|
83
|
+
.class-name-in-header {
|
84
|
+
font-size: 180%;
|
85
|
+
font-weight: bold;
|
86
|
+
}
|
87
|
+
|
88
|
+
|
89
|
+
div#bodyContent {
|
90
|
+
padding: 0 1.5em 0 1.5em;
|
91
|
+
}
|
92
|
+
|
93
|
+
div#description {
|
94
|
+
padding: 0.5em 1.5em;
|
95
|
+
background: #efefef;
|
96
|
+
border: 1px dotted #999;
|
97
|
+
}
|
98
|
+
|
99
|
+
div#description h1,h2,h3,h4,h5,h6 {
|
100
|
+
color: #125;;
|
101
|
+
background: transparent;
|
102
|
+
}
|
103
|
+
|
104
|
+
div#validator-badges {
|
105
|
+
text-align: center;
|
106
|
+
}
|
107
|
+
div#validator-badges img { border: 0; }
|
108
|
+
|
109
|
+
div#copyright {
|
110
|
+
color: #333;
|
111
|
+
background: #efefef;
|
112
|
+
font: 0.75em sans-serif;
|
113
|
+
margin-top: 5em;
|
114
|
+
margin-bottom: 0;
|
115
|
+
padding: 0.5em 2em;
|
116
|
+
}
|
117
|
+
|
118
|
+
|
119
|
+
/* === Classes =================================== */
|
120
|
+
|
121
|
+
table.header-table {
|
122
|
+
color: white;
|
123
|
+
font-size: small;
|
124
|
+
}
|
125
|
+
|
126
|
+
.type-note {
|
127
|
+
font-size: small;
|
128
|
+
color: #DEDEDE;
|
129
|
+
}
|
130
|
+
|
131
|
+
.xxsection-bar {
|
132
|
+
background: #eee;
|
133
|
+
color: #333;
|
134
|
+
padding: 3px;
|
135
|
+
}
|
136
|
+
|
137
|
+
.section-bar {
|
138
|
+
color: #333;
|
139
|
+
border-bottom: 1px solid #999;
|
140
|
+
margin-left: -20px;
|
141
|
+
}
|
142
|
+
|
143
|
+
|
144
|
+
.section-title {
|
145
|
+
background: #79a;
|
146
|
+
color: #eee;
|
147
|
+
padding: 3px;
|
148
|
+
margin-top: 2em;
|
149
|
+
margin-left: -30px;
|
150
|
+
border: 1px solid #999;
|
151
|
+
}
|
152
|
+
|
153
|
+
.top-aligned-row { vertical-align: top }
|
154
|
+
.bottom-aligned-row { vertical-align: bottom }
|
155
|
+
|
156
|
+
/* --- Context section classes ----------------------- */
|
157
|
+
|
158
|
+
.context-row { }
|
159
|
+
.context-item-name { font-family: monospace; font-weight: bold; color: black; }
|
160
|
+
.context-item-value { font-size: small; color: #448; }
|
161
|
+
.context-item-desc { color: #333; padding-left: 2em; }
|
162
|
+
|
163
|
+
/* --- Method classes -------------------------- */
|
164
|
+
.method-detail {
|
165
|
+
background: #efefef;
|
166
|
+
padding: 0;
|
167
|
+
margin-top: 0.5em;
|
168
|
+
margin-bottom: 1em;
|
169
|
+
border: 1px dotted #ccc;
|
170
|
+
}
|
171
|
+
.method-heading {
|
172
|
+
color: black;
|
173
|
+
background: #ccc;
|
174
|
+
border-bottom: 1px solid #666;
|
175
|
+
padding: 0.2em 0.5em 0 0.5em;
|
176
|
+
}
|
177
|
+
.method-signature { color: black; background: inherit; }
|
178
|
+
.method-name { font-weight: bold; }
|
179
|
+
.method-args { font-style: italic; }
|
180
|
+
.method-description { padding: 0 0.5em 0 0.5em; }
|
181
|
+
|
182
|
+
/* --- Source code sections -------------------- */
|
183
|
+
|
184
|
+
a.source-toggle { font-size: 90%; }
|
185
|
+
div.method-source-code {
|
186
|
+
background: #262626;
|
187
|
+
color: #ffdead;
|
188
|
+
margin: 1em;
|
189
|
+
padding: 0.5em;
|
190
|
+
border: 1px dashed #999;
|
191
|
+
overflow: hidden;
|
192
|
+
}
|
193
|
+
|
194
|
+
div.method-source-code pre { color: #ffdead; overflow: hidden; }
|
195
|
+
|
196
|
+
/* --- Ruby keyword styles --------------------- */
|
197
|
+
|
198
|
+
.standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
|
199
|
+
|
200
|
+
.ruby-constant { color: #7fffd4; background: transparent; }
|
201
|
+
.ruby-keyword { color: #00ffff; background: transparent; }
|
202
|
+
.ruby-ivar { color: #eedd82; background: transparent; }
|
203
|
+
.ruby-operator { color: #00ffee; background: transparent; }
|
204
|
+
.ruby-identifier { color: #ffdead; background: transparent; }
|
205
|
+
.ruby-node { color: #ffa07a; background: transparent; }
|
206
|
+
.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
|
207
|
+
.ruby-regexp { color: #ffa07a; background: transparent; }
|
208
|
+
.ruby-value { color: #7fffd4; background: transparent; }
|
data/demo/lib/foo/foo.rb
ADDED
data/demo/util/conf/rdoc
ADDED
data/demo/util/one
ADDED
data/demo/util/rdoc
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Generate RDocs
|
4
|
+
|
5
|
+
# Check for 'doc' directory.
|
6
|
+
# (Helps to ensure we're in the right place.)
|
7
|
+
|
8
|
+
require 'ratchets/batch'
|
9
|
+
|
10
|
+
dir! 'doc'
|
11
|
+
|
12
|
+
# Load rdoc configuration.
|
13
|
+
|
14
|
+
config = config_load('rdoc')
|
15
|
+
|
16
|
+
config = {
|
17
|
+
'template' => 'html',
|
18
|
+
'op' => 'doc/rdoc',
|
19
|
+
'merge' => true,
|
20
|
+
'inline-source' => true,
|
21
|
+
'exclude' => %w{ InstalledFiles Manifest Project dev util },
|
22
|
+
'include' => %w{ [A-Z]* lib }
|
23
|
+
}.update config
|
24
|
+
|
25
|
+
# Prepare command arguments.
|
26
|
+
|
27
|
+
vector = config_vector(config, 'include')
|
28
|
+
|
29
|
+
# Remove old rdocs, if any.
|
30
|
+
|
31
|
+
dir = config['op']
|
32
|
+
|
33
|
+
abort "bad ouput directory #{dir}" if dir =~ /^\//
|
34
|
+
|
35
|
+
rm_r dir if dir?(dir)
|
36
|
+
|
37
|
+
# Document.
|
38
|
+
|
39
|
+
rdoc(*vector)
|
data/demo/util/tryme
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# Module extension for defining prequisite tasks.
|
2
|
+
|
3
|
+
module Taskable
|
4
|
+
|
5
|
+
# Define or call a task.
|
6
|
+
|
7
|
+
def task n, &block
|
8
|
+
case n
|
9
|
+
when Hash
|
10
|
+
name, preq = *n.to_a[0]
|
11
|
+
else
|
12
|
+
name, preq = n, []
|
13
|
+
end
|
14
|
+
|
15
|
+
task_name = "#{name}:task"
|
16
|
+
|
17
|
+
define_method(task_name) do |cache,*args|
|
18
|
+
cache ||= {}
|
19
|
+
return cache[name] if cache.key?(name)
|
20
|
+
preq.each do |q|
|
21
|
+
send("#{q}:task",cache,*args)
|
22
|
+
end
|
23
|
+
cache[name] = block.call(*args)
|
24
|
+
end
|
25
|
+
|
26
|
+
private task_name
|
27
|
+
end
|
28
|
+
|
29
|
+
def call_target(name,*a)
|
30
|
+
send("#{name}:task",nil,*a)
|
31
|
+
end
|
32
|
+
|
33
|
+
#def cache
|
34
|
+
# @taskable_cache ||= {}
|
35
|
+
#end
|
36
|
+
|
37
|
+
#def function s, &b
|
38
|
+
# define_method s, &b
|
39
|
+
# private s
|
40
|
+
#end
|
41
|
+
|
42
|
+
end
|
data/dev/taskable.rb
ADDED
@@ -0,0 +1,573 @@
|
|
1
|
+
# TITLE:
|
2
|
+
#
|
3
|
+
# Taskable
|
4
|
+
#
|
5
|
+
# COPYRIGHT:
|
6
|
+
#
|
7
|
+
# Copyright (c) 2006 Thomas Sawyer
|
8
|
+
#
|
9
|
+
# LICENSE:
|
10
|
+
#
|
11
|
+
# Ruby License
|
12
|
+
#
|
13
|
+
# This module is free software. You may use, modify, and/or redistribute this
|
14
|
+
# software under the same terms as Ruby.
|
15
|
+
#
|
16
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
17
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
18
|
+
# FOR A PARTICULAR PURPOSE.
|
19
|
+
#
|
20
|
+
# AUTHORS:
|
21
|
+
#
|
22
|
+
# - Thomas Sawyer
|
23
|
+
#
|
24
|
+
# NOTES:
|
25
|
+
#
|
26
|
+
# - TODO The included call back does a comparison to Object.
|
27
|
+
# This is a bit of a hack b/c there is actually no way to
|
28
|
+
# check if it is the toplevel --a flaw w/ Ruby's toplevel proxy.
|
29
|
+
#
|
30
|
+
# - TODO Should Rake's namespace feature be added? This could interfer
|
31
|
+
# with other definitions of #namespace.
|
32
|
+
#
|
33
|
+
# - TODO The only reason the :exec method is defined is b/c instance_exec
|
34
|
+
# is not in Ruby yet, so until then this is the working hack.
|
35
|
+
#
|
36
|
+
# LOG:
|
37
|
+
#
|
38
|
+
# - CHANGE 2006-11-14 trans
|
39
|
+
#
|
40
|
+
# Taskable has been completely rewritten. While it is essentially
|
41
|
+
# compatible with the previous implementation, it is not 100% the
|
42
|
+
# same; mainly in that tasks are not defined as methods any longer.
|
43
|
+
# This new implementation is now nearly 100% compatible with Rake's
|
44
|
+
# design. Note, for a basic "taskable" system, more like the old
|
45
|
+
# version, see depend.rb.
|
46
|
+
|
47
|
+
require 'facets/class_extension'
|
48
|
+
|
49
|
+
$toplevel = self
|
50
|
+
|
51
|
+
# = Taskable
|
52
|
+
#
|
53
|
+
# The Taskable module provides a generic task system
|
54
|
+
# patterned after Rake, but useable in any
|
55
|
+
# code context --not just with the Rake tool. In other
|
56
|
+
# words one can create methods with dependencies.
|
57
|
+
#
|
58
|
+
# NOTE Unlike methods, tasks can't take independent parameters
|
59
|
+
# if they are to be used as prerequisites. The arguments passed
|
60
|
+
# to a task call will also be passed to it's prequisites.
|
61
|
+
#
|
62
|
+
# To use Taskable at the toplevel use:
|
63
|
+
#
|
64
|
+
# include Taskable
|
65
|
+
#
|
66
|
+
# Or if you want all modules to be "taskable":
|
67
|
+
#
|
68
|
+
# class Module
|
69
|
+
# include Taskable
|
70
|
+
# end
|
71
|
+
|
72
|
+
module Taskable
|
73
|
+
|
74
|
+
def self.included( base )
|
75
|
+
if base == Object #$toplevel
|
76
|
+
require 'facets/more/main_as_module.rb'
|
77
|
+
Module.module_eval{ include TaskableDSL }
|
78
|
+
else
|
79
|
+
base.extend TaskableDSL
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
### CLASS LEVEL ###
|
84
|
+
|
85
|
+
module TaskableDSL
|
86
|
+
|
87
|
+
#--
|
88
|
+
# TODO Add task namespace functionality ???
|
89
|
+
#++
|
90
|
+
#def namespace
|
91
|
+
#end
|
92
|
+
|
93
|
+
# Define description for subsequent task.
|
94
|
+
|
95
|
+
def desc(line=nil)
|
96
|
+
return @_last_description unless line
|
97
|
+
@_last_description = line.gsub("\n",'')
|
98
|
+
end
|
99
|
+
|
100
|
+
# Use up the description for subsequent task.
|
101
|
+
|
102
|
+
def desc!
|
103
|
+
l, @_last_description = @_last_description, nil
|
104
|
+
l
|
105
|
+
end
|
106
|
+
|
107
|
+
# <b>Task</b>
|
108
|
+
#
|
109
|
+
#
|
110
|
+
|
111
|
+
def task( target_to_source, &build )
|
112
|
+
target, source = *Task.parse(target_to_source)
|
113
|
+
define_method("#{target}:exec",&build) if build
|
114
|
+
(@task||={})[target] = Task.new(target, source, desc!, &build)
|
115
|
+
end
|
116
|
+
|
117
|
+
# <b>File task</b>
|
118
|
+
#
|
119
|
+
# Task must be provide instructions for building the file.
|
120
|
+
|
121
|
+
def file( file_to_source, &build )
|
122
|
+
file, source = *Task.parse(file_to_source)
|
123
|
+
define_method("#{file}:exec",&build) if build
|
124
|
+
(@task||={})[file] = FileTask.new(file, source, desc!, &build)
|
125
|
+
end
|
126
|
+
|
127
|
+
# <b>Rule task</b>
|
128
|
+
#
|
129
|
+
# Task must be provide instructions for building the file(s).
|
130
|
+
|
131
|
+
def rule( pattern_to_source, &build )
|
132
|
+
pattern, source = *Task.parse(pattern_to_source)
|
133
|
+
define_method("#{pattern}:exec",&build) if build
|
134
|
+
(@task||={})[pattern] = RuleTask.new(pattern, source, desc!, &build)
|
135
|
+
end
|
136
|
+
|
137
|
+
#
|
138
|
+
|
139
|
+
def instance_tasks( ancestry=true )
|
140
|
+
@task ||= {}
|
141
|
+
if ancestry
|
142
|
+
ancestors.inject(@task.keys) do |m,a|
|
143
|
+
t = a.instance_variable_get("@task")
|
144
|
+
m |= t.keys if t
|
145
|
+
m
|
146
|
+
end
|
147
|
+
else
|
148
|
+
@task.keys
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# List of task names with descriptions.
|
153
|
+
|
154
|
+
def described_tasks( ancestry=true )
|
155
|
+
memo = []
|
156
|
+
instance_tasks(ancestry).each do |name|
|
157
|
+
memo << name if @task[name].desc
|
158
|
+
end
|
159
|
+
return memo
|
160
|
+
end
|
161
|
+
|
162
|
+
# List of task names without descriptions.
|
163
|
+
|
164
|
+
def undescribed_tasks( ancestry=true )
|
165
|
+
memo = []
|
166
|
+
instance_tasks(ancestry).each do |name|
|
167
|
+
memo << name unless @task[name].desc
|
168
|
+
end
|
169
|
+
return memo
|
170
|
+
end
|
171
|
+
|
172
|
+
# Find matching task.
|
173
|
+
#--
|
174
|
+
# TODO Maybe this isn't really needed here and can be moved to Task class ???
|
175
|
+
#++
|
176
|
+
|
177
|
+
def instance_task( match )
|
178
|
+
hit = (@task||={}).values.find do |task|
|
179
|
+
task.match(match)
|
180
|
+
end
|
181
|
+
return hit if hit
|
182
|
+
ancestors.each do |a|
|
183
|
+
task_table = a.instance_variable_get("@task")
|
184
|
+
next unless task_table
|
185
|
+
hit = task_table.values.find do |task|
|
186
|
+
task.match(match)
|
187
|
+
end
|
188
|
+
break hit if hit
|
189
|
+
end
|
190
|
+
hit
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
### INSTANCE LEVEL ###
|
196
|
+
|
197
|
+
#
|
198
|
+
|
199
|
+
def tasks
|
200
|
+
(class << self; self; end).instance_tasks
|
201
|
+
end
|
202
|
+
|
203
|
+
#
|
204
|
+
|
205
|
+
def task(name)
|
206
|
+
(class << self; self; end).instance_task(name)
|
207
|
+
end
|
208
|
+
|
209
|
+
# FIXME, THIS STILL WONT WORK AT TOPLEVEL!!!!
|
210
|
+
|
211
|
+
def method_missing(t, *a, &b)
|
212
|
+
p t
|
213
|
+
p tasks
|
214
|
+
p task(t)
|
215
|
+
#if self.class.respond_to?(:instance_task) && (task = self.class.instance_task(t))
|
216
|
+
if tsk = task(t)
|
217
|
+
tsk.run(self, t)
|
218
|
+
else
|
219
|
+
super(t.to_sym,*a,&b)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
224
|
+
|
225
|
+
#
|
226
|
+
|
227
|
+
class Taskable::Task
|
228
|
+
|
229
|
+
# Parse target => [source,...] argument.
|
230
|
+
|
231
|
+
def self.parse(target_to_source)
|
232
|
+
if Hash === target_to_source
|
233
|
+
target = target_to_source.keys[0]
|
234
|
+
source = target_to_source.values[0]
|
235
|
+
else
|
236
|
+
target = target_to_source
|
237
|
+
source = []
|
238
|
+
end
|
239
|
+
return target.to_sym, source.collect{|s| s.to_sym}
|
240
|
+
end
|
241
|
+
|
242
|
+
#
|
243
|
+
|
244
|
+
attr_reader :target, :source, :desc, :build
|
245
|
+
|
246
|
+
alias :name :target
|
247
|
+
alias :description :desc
|
248
|
+
|
249
|
+
# New task.
|
250
|
+
|
251
|
+
def initialize( target, source, desc=nil, &build )
|
252
|
+
@target = target
|
253
|
+
@source = source
|
254
|
+
@desc = desc
|
255
|
+
@build = build
|
256
|
+
end
|
257
|
+
|
258
|
+
# Run task in given context.
|
259
|
+
|
260
|
+
def run( context, target )
|
261
|
+
task = self
|
262
|
+
source = @source
|
263
|
+
build = @build
|
264
|
+
|
265
|
+
presource(context).each do |d|
|
266
|
+
d.call(context)
|
267
|
+
end
|
268
|
+
|
269
|
+
call(context)
|
270
|
+
end
|
271
|
+
|
272
|
+
# Call build exec of task. Note that the use of :exec method
|
273
|
+
# is due to the lack of #instance_exec which will come wiht Ruby 1.9.
|
274
|
+
|
275
|
+
def call( context )
|
276
|
+
context.send("#{@target}:exec", self) if @build
|
277
|
+
end
|
278
|
+
|
279
|
+
#
|
280
|
+
|
281
|
+
def match( target )
|
282
|
+
@target.to_s == target.to_s
|
283
|
+
end
|
284
|
+
|
285
|
+
# Compile list of all unique prerequisite sources.
|
286
|
+
|
287
|
+
def presource( context, build=[] )
|
288
|
+
@source.each do |s|
|
289
|
+
t = context.class.instance_task(s)
|
290
|
+
raise NoMethodError, 'undefined source' unless t
|
291
|
+
build.unshift(t)
|
292
|
+
t.presource(context,build)
|
293
|
+
end
|
294
|
+
build.uniq!
|
295
|
+
build
|
296
|
+
end
|
297
|
+
|
298
|
+
end
|
299
|
+
|
300
|
+
#
|
301
|
+
|
302
|
+
class Taskable::FileTask < Taskable::Task
|
303
|
+
|
304
|
+
# Run file task in a given context.
|
305
|
+
|
306
|
+
def run( context, target )
|
307
|
+
task = self
|
308
|
+
source = @source
|
309
|
+
build = @build
|
310
|
+
|
311
|
+
context.instance_eval do
|
312
|
+
needed = false
|
313
|
+
if File.exist?(file)
|
314
|
+
#source.each { |s| send(s) if respond_to?(s) }
|
315
|
+
timestamp = File.mtime(file)
|
316
|
+
needed = source.any? { |f| File.mtime(f.to_s) > timestamp }
|
317
|
+
else
|
318
|
+
timestamp = Time.now - 1
|
319
|
+
needed = true
|
320
|
+
end
|
321
|
+
if needed
|
322
|
+
build.call(task)
|
323
|
+
unless File.exist?(file) and File.mtime(file) > timestamp
|
324
|
+
raise "failed to build -- #{file}"
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
#
|
331
|
+
|
332
|
+
def match(target)
|
333
|
+
@target.to_s == target.to_s
|
334
|
+
end
|
335
|
+
|
336
|
+
end
|
337
|
+
|
338
|
+
#
|
339
|
+
|
340
|
+
class Taskable::RuleTask < Taskable::FileTask
|
341
|
+
|
342
|
+
# Run rule task in given context.
|
343
|
+
|
344
|
+
def run( context, target )
|
345
|
+
@target = target
|
346
|
+
super(context)
|
347
|
+
end
|
348
|
+
|
349
|
+
#
|
350
|
+
|
351
|
+
def match(target)
|
352
|
+
case @target
|
353
|
+
when Regexp
|
354
|
+
@target =~ target.to_s
|
355
|
+
when String
|
356
|
+
#if @target.index('*') #TODO
|
357
|
+
# /#{@target.gsub('*', '.*?')}/ =~ target
|
358
|
+
if @target.index('.') == 0
|
359
|
+
/#{Regexp.escape(@target)}$/ =~ target
|
360
|
+
else
|
361
|
+
super
|
362
|
+
end
|
363
|
+
else
|
364
|
+
super
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
end
|
369
|
+
|
370
|
+
|
371
|
+
|
372
|
+
# _____ _
|
373
|
+
# |_ _|__ ___| |_
|
374
|
+
# | |/ _ \/ __| __|
|
375
|
+
# | | __/\__ \ |_
|
376
|
+
# |_|\___||___/\__|
|
377
|
+
#
|
378
|
+
=begin ##test
|
379
|
+
|
380
|
+
require 'test/unit'
|
381
|
+
|
382
|
+
class TestTaskable1 < Test::Unit::TestCase
|
383
|
+
|
384
|
+
module M
|
385
|
+
include Taskable
|
386
|
+
task :m1 => [ :c1 ] do @x << "m1" end
|
387
|
+
task :m2 => [ :c2 ] do @x << "m2" end
|
388
|
+
task :m3 => [ :c3 ] do @x << "m3" end
|
389
|
+
task :m4 => [ :c1, :c2, :c3 ] do @x << "m4" end
|
390
|
+
task :m5 do @x << 'm5' end
|
391
|
+
end
|
392
|
+
|
393
|
+
class B
|
394
|
+
include Taskable
|
395
|
+
attr :x
|
396
|
+
def initialize ; @x = [] ; end
|
397
|
+
|
398
|
+
desc "test-b1"
|
399
|
+
task :b1 do @x << "b1" end
|
400
|
+
task :b2 => [ :b1 ]
|
401
|
+
end
|
402
|
+
|
403
|
+
class C
|
404
|
+
include M
|
405
|
+
attr :x
|
406
|
+
def initialize ; @x = [] ; end
|
407
|
+
|
408
|
+
task :c1 do @x << "c1" end
|
409
|
+
task :c2 => [ :c1, :c1 ] do @x << "c2" end
|
410
|
+
task :c3 => [ :c1, :c2 ] do @x << "c3" end
|
411
|
+
task :c4 => [ :m1 ] do @x << "c4" end
|
412
|
+
task :c5 => [ :c5 ] do @x << "c5" end
|
413
|
+
task :c6 => [ :c7 ] do @x << "c6" end
|
414
|
+
task :c7 => [ :c6 ] do @x << "c7" end
|
415
|
+
end
|
416
|
+
|
417
|
+
class D < C
|
418
|
+
task :d1 => [ :c1 ] do @x << "d1" ; end
|
419
|
+
task :d2 => [ :m1 ] do @x << "d2" ; end
|
420
|
+
end
|
421
|
+
|
422
|
+
module N
|
423
|
+
include M
|
424
|
+
end
|
425
|
+
|
426
|
+
class E
|
427
|
+
include N
|
428
|
+
attr :x
|
429
|
+
def initialize ; @x = [] ; end
|
430
|
+
|
431
|
+
task :e1 => [ :c1 ] do @x << "e1" ; end
|
432
|
+
task :e2 => [ :m1 ] do @x << "e2" ; end
|
433
|
+
task :e3 => [ :m5 ] do @x << "e3" ; end
|
434
|
+
end
|
435
|
+
|
436
|
+
module O
|
437
|
+
include Taskable
|
438
|
+
attr :x
|
439
|
+
task :o1 do (@x||=[]) << "o1" end
|
440
|
+
task :o2 => [ :o1 ] do (@x||=[]) << "o2" end
|
441
|
+
end
|
442
|
+
|
443
|
+
# tests
|
444
|
+
|
445
|
+
def test_001
|
446
|
+
assert( B.described_tasks.include?(:b1) )
|
447
|
+
end
|
448
|
+
|
449
|
+
def test_B1
|
450
|
+
b = B.new ; b.b1
|
451
|
+
assert_equal( [ 'b1' ], b.x )
|
452
|
+
end
|
453
|
+
|
454
|
+
def test_B2
|
455
|
+
b = B.new ; b.b2
|
456
|
+
assert_equal( [ 'b1' ], b.x )
|
457
|
+
end
|
458
|
+
|
459
|
+
def test_C1
|
460
|
+
c = C.new ; c.c1
|
461
|
+
assert_equal( [ 'c1' ], c.x )
|
462
|
+
end
|
463
|
+
|
464
|
+
def test_C2
|
465
|
+
c = C.new ; c.c2
|
466
|
+
assert_equal( [ 'c1', 'c2' ], c.x )
|
467
|
+
end
|
468
|
+
|
469
|
+
def test_C3
|
470
|
+
c = C.new ; c.c3
|
471
|
+
assert_equal( [ 'c1', 'c2', 'c3' ], c.x )
|
472
|
+
end
|
473
|
+
|
474
|
+
def test_C4
|
475
|
+
c = C.new ; c.c4
|
476
|
+
assert_equal( [ 'c1', 'm1', 'c4' ], c.x )
|
477
|
+
end
|
478
|
+
|
479
|
+
def test_M1
|
480
|
+
c = C.new ; c.m1
|
481
|
+
assert_equal( [ 'c1', 'm1' ], c.x )
|
482
|
+
end
|
483
|
+
|
484
|
+
def test_M2
|
485
|
+
c = C.new ; c.m2
|
486
|
+
assert_equal( [ 'c1', 'c2', 'm2' ], c.x )
|
487
|
+
end
|
488
|
+
|
489
|
+
def test_M3
|
490
|
+
c = C.new ; c.m3
|
491
|
+
assert_equal( [ 'c1', 'c2', 'c3', 'm3' ], c.x )
|
492
|
+
end
|
493
|
+
|
494
|
+
def test_M4
|
495
|
+
c = C.new ; c.m4
|
496
|
+
assert_equal( [ 'c1', 'c2', 'c3', 'm4' ], c.x )
|
497
|
+
end
|
498
|
+
|
499
|
+
def test_D1
|
500
|
+
d = D.new ; d.d1
|
501
|
+
assert_equal( [ 'c1', 'd1' ], d.x )
|
502
|
+
end
|
503
|
+
|
504
|
+
def test_D2
|
505
|
+
d = D.new ; d.d2
|
506
|
+
assert_equal( [ 'c1', 'm1', 'd2' ], d.x )
|
507
|
+
end
|
508
|
+
|
509
|
+
def test_E1
|
510
|
+
e = E.new
|
511
|
+
assert_raises( NoMethodError ) { e.e1 }
|
512
|
+
#assert_equal( [ 'c1', 'e1' ], e.x )
|
513
|
+
end
|
514
|
+
|
515
|
+
def test_E2
|
516
|
+
e = E.new
|
517
|
+
assert_raises( NoMethodError ) { e.e2 }
|
518
|
+
#assert_equal( [ 'c1', 'm1', 'e2' ], e.x )
|
519
|
+
end
|
520
|
+
|
521
|
+
def test_E3
|
522
|
+
e = E.new ; e.e3
|
523
|
+
assert_equal( [ 'm5', 'e3' ], e.x )
|
524
|
+
end
|
525
|
+
|
526
|
+
# def test_F1
|
527
|
+
# F.o1
|
528
|
+
# assert_equal( [ 'o1' ], F.x )
|
529
|
+
# end
|
530
|
+
#
|
531
|
+
# def test_F2
|
532
|
+
# F.o2
|
533
|
+
# assert_equal( [ 'o1', 'o1', 'o2' ], F.x )
|
534
|
+
# end
|
535
|
+
|
536
|
+
end
|
537
|
+
|
538
|
+
=end
|
539
|
+
|
540
|
+
##
|
541
|
+
# Test toplevel usage.
|
542
|
+
#
|
543
|
+
|
544
|
+
include Taskable
|
545
|
+
|
546
|
+
p Object.ancestors
|
547
|
+
|
548
|
+
task :foo do
|
549
|
+
"foo"
|
550
|
+
end
|
551
|
+
|
552
|
+
task :bar => [ :foo ] do
|
553
|
+
"bar"
|
554
|
+
end
|
555
|
+
|
556
|
+
#class TestTaskable2 #< Test::Unit::TestCase
|
557
|
+
def test_01
|
558
|
+
puts foo
|
559
|
+
end
|
560
|
+
|
561
|
+
def test_02
|
562
|
+
puts bar
|
563
|
+
end
|
564
|
+
#end
|
565
|
+
|
566
|
+
test_01
|
567
|
+
test_02
|
568
|
+
|
569
|
+
#=end
|
570
|
+
|
571
|
+
# Author:: Thomas Sawyer
|
572
|
+
# Copyright:: Copyright (c) 2006 Thomas Sawyer
|
573
|
+
# License:: Ruby License
|