jbarnette-johnson 1.0.0.200806240111
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/CHANGELOG +5 -0
- data/MANIFEST +385 -0
- data/MINGW32.mk +124 -0
- data/README.rdoc +51 -0
- data/Rakefile +166 -0
- data/bin/johnson +107 -0
- data/cross-compile.txt +38 -0
- data/ext/spidermonkey/context.c +122 -0
- data/ext/spidermonkey/context.h +19 -0
- data/ext/spidermonkey/conversions.c +286 -0
- data/ext/spidermonkey/conversions.h +18 -0
- data/ext/spidermonkey/debugger.c +208 -0
- data/ext/spidermonkey/debugger.h +9 -0
- data/ext/spidermonkey/extconf.rb +25 -0
- data/ext/spidermonkey/extensions.c +37 -0
- data/ext/spidermonkey/extensions.h +12 -0
- data/ext/spidermonkey/global.c +40 -0
- data/ext/spidermonkey/global.h +11 -0
- data/ext/spidermonkey/idhash.c +16 -0
- data/ext/spidermonkey/idhash.h +8 -0
- data/ext/spidermonkey/immutable_node.c.erb +522 -0
- data/ext/spidermonkey/immutable_node.h +22 -0
- data/ext/spidermonkey/jroot.h +187 -0
- data/ext/spidermonkey/js_land_proxy.c +609 -0
- data/ext/spidermonkey/js_land_proxy.h +20 -0
- data/ext/spidermonkey/ruby_land_proxy.c +537 -0
- data/ext/spidermonkey/ruby_land_proxy.h +17 -0
- data/ext/spidermonkey/runtime.c +304 -0
- data/ext/spidermonkey/runtime.h +25 -0
- data/ext/spidermonkey/spidermonkey.c +20 -0
- data/ext/spidermonkey/spidermonkey.h +29 -0
- data/js/johnson/browser.js +9 -0
- data/js/johnson/browser/env.js +687 -0
- data/js/johnson/browser/jquery.js +3444 -0
- data/js/johnson/browser/xmlsax.js +1564 -0
- data/js/johnson/browser/xmlw3cdom.js +4189 -0
- data/js/johnson/cli.js +30 -0
- data/js/johnson/prelude.js +80 -0
- data/js/johnson/template.js +29 -0
- data/lib/hoe.rb +748 -0
- data/lib/johnson.rb +46 -0
- data/lib/johnson/cli.rb +7 -0
- data/lib/johnson/cli/options.rb +56 -0
- data/lib/johnson/error.rb +4 -0
- data/lib/johnson/nodes.rb +7 -0
- data/lib/johnson/nodes/binary_node.rb +64 -0
- data/lib/johnson/nodes/for.rb +14 -0
- data/lib/johnson/nodes/for_in.rb +12 -0
- data/lib/johnson/nodes/function.rb +13 -0
- data/lib/johnson/nodes/list.rb +27 -0
- data/lib/johnson/nodes/node.rb +68 -0
- data/lib/johnson/nodes/ternary_node.rb +20 -0
- data/lib/johnson/parser.rb +21 -0
- data/lib/johnson/parser/syntax_error.rb +13 -0
- data/lib/johnson/runtime.rb +55 -0
- data/lib/johnson/spidermonkey/context.rb +10 -0
- data/lib/johnson/spidermonkey/debugger.rb +67 -0
- data/lib/johnson/spidermonkey/immutable_node.rb +280 -0
- data/lib/johnson/spidermonkey/js_land_proxy.rb +62 -0
- data/lib/johnson/spidermonkey/mutable_tree_visitor.rb +233 -0
- data/lib/johnson/spidermonkey/ruby_land_proxy.rb +52 -0
- data/lib/johnson/spidermonkey/runtime.rb +94 -0
- data/lib/johnson/version.rb +4 -0
- data/lib/johnson/visitable.rb +16 -0
- data/lib/johnson/visitors.rb +4 -0
- data/lib/johnson/visitors/dot_visitor.rb +167 -0
- data/lib/johnson/visitors/ecma_visitor.rb +315 -0
- data/lib/johnson/visitors/enumerating_visitor.rb +115 -0
- data/lib/johnson/visitors/sexp_visitor.rb +172 -0
- data/lib/rails/init.rb +37 -0
- data/test/assets/index.html +38 -0
- data/test/assets/jquery_test.html +186 -0
- data/test/helper.rb +58 -0
- data/test/johnson/browser_test.rb +38 -0
- data/test/johnson/conversions/array_test.rb +32 -0
- data/test/johnson/conversions/boolean_test.rb +17 -0
- data/test/johnson/conversions/callable_test.rb +34 -0
- data/test/johnson/conversions/file_test.rb +15 -0
- data/test/johnson/conversions/nil_test.rb +20 -0
- data/test/johnson/conversions/number_test.rb +34 -0
- data/test/johnson/conversions/regexp_test.rb +24 -0
- data/test/johnson/conversions/string_test.rb +26 -0
- data/test/johnson/conversions/struct_test.rb +15 -0
- data/test/johnson/conversions/symbol_test.rb +19 -0
- data/test/johnson/conversions/thread_test.rb +24 -0
- data/test/johnson/error_test.rb +9 -0
- data/test/johnson/extensions_test.rb +56 -0
- data/test/johnson/nodes/array_literal_test.rb +57 -0
- data/test/johnson/nodes/array_node_test.rb +26 -0
- data/test/johnson/nodes/binary_node_test.rb +61 -0
- data/test/johnson/nodes/bracket_access_test.rb +16 -0
- data/test/johnson/nodes/delete_test.rb +11 -0
- data/test/johnson/nodes/do_while_test.rb +12 -0
- data/test/johnson/nodes/dot_accessor_test.rb +15 -0
- data/test/johnson/nodes/export_test.rb +9 -0
- data/test/johnson/nodes/for_test.rb +54 -0
- data/test/johnson/nodes/function_test.rb +71 -0
- data/test/johnson/nodes/if_test.rb +41 -0
- data/test/johnson/nodes/import_test.rb +13 -0
- data/test/johnson/nodes/label_test.rb +19 -0
- data/test/johnson/nodes/object_literal_test.rb +110 -0
- data/test/johnson/nodes/return_test.rb +16 -0
- data/test/johnson/nodes/semi_test.rb +8 -0
- data/test/johnson/nodes/switch_test.rb +55 -0
- data/test/johnson/nodes/ternary_test.rb +25 -0
- data/test/johnson/nodes/throw_test.rb +9 -0
- data/test/johnson/nodes/try_node_test.rb +59 -0
- data/test/johnson/nodes/typeof_test.rb +11 -0
- data/test/johnson/nodes/unary_node_test.rb +23 -0
- data/test/johnson/nodes/void_test.rb +11 -0
- data/test/johnson/nodes/while_test.rb +26 -0
- data/test/johnson/nodes/with_test.rb +10 -0
- data/test/johnson/prelude_test.rb +56 -0
- data/test/johnson/runtime_test.rb +46 -0
- data/test/johnson/spidermonkey/context_test.rb +21 -0
- data/test/johnson/spidermonkey/immutable_node_test.rb +34 -0
- data/test/johnson/spidermonkey/js_land_proxy_test.rb +236 -0
- data/test/johnson/spidermonkey/ruby_land_proxy_test.rb +225 -0
- data/test/johnson/spidermonkey/runtime_test.rb +17 -0
- data/test/johnson/version_test.rb +13 -0
- data/test/johnson/visitors/dot_visitor_test.rb +39 -0
- data/test/johnson/visitors/enumerating_visitor_test.rb +12 -0
- data/test/johnson_test.rb +16 -0
- data/test/jquery_units/test.js +27 -0
- data/test/jquery_units/test_helper.js +197 -0
- data/test/jquery_units/units/ajax.js +795 -0
- data/test/jquery_units/units/core.js +1563 -0
- data/test/jquery_units/units/event.js +299 -0
- data/test/jquery_units/units/fx.js +427 -0
- data/test/jquery_units/units/offset.js +112 -0
- data/test/jquery_units/units/selector.js +224 -0
- data/test/jspec/helper.js +7 -0
- data/test/jspec/jspec.js +192 -0
- data/test/jspec/simple_spec.js +68 -0
- data/test/parser_test.rb +276 -0
- data/todo/.keep +0 -0
- metadata +501 -0
data/js/johnson/cli.js
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
Ruby.require("uri");
|
2
|
+
Ruby.require("open-uri");
|
3
|
+
|
4
|
+
function load() {
|
5
|
+
for (var i = 0; i < arguments.length; ++i)
|
6
|
+
Johnson.require(arguments[i]);
|
7
|
+
}
|
8
|
+
|
9
|
+
function print() {
|
10
|
+
for (var i = 0; i < arguments.length; ++i)
|
11
|
+
Ruby.puts(arguments[i]);
|
12
|
+
}
|
13
|
+
|
14
|
+
// NOTE: the Rhino version takes an optional encoding
|
15
|
+
function readFile(path) {
|
16
|
+
return Ruby.IO.read(path);
|
17
|
+
}
|
18
|
+
|
19
|
+
// NOTE: the Rhino version takes an optional encoding
|
20
|
+
function readUrl(url) {
|
21
|
+
return Ruby.URI.parse(url).read();
|
22
|
+
}
|
23
|
+
|
24
|
+
function quit() {
|
25
|
+
Ruby.exit();
|
26
|
+
}
|
27
|
+
|
28
|
+
function version() {
|
29
|
+
return Ruby.Johnson.VERSION;
|
30
|
+
}
|
@@ -0,0 +1,80 @@
|
|
1
|
+
var Johnson = {};
|
2
|
+
|
3
|
+
Johnson.Symbol = function(string) {
|
4
|
+
this.string = string;
|
5
|
+
};
|
6
|
+
|
7
|
+
Johnson.Symbol.prototype = {
|
8
|
+
toString: function() {
|
9
|
+
return this.string;
|
10
|
+
},
|
11
|
+
|
12
|
+
inspect: function() {
|
13
|
+
return ":" + this.toString();
|
14
|
+
}
|
15
|
+
};
|
16
|
+
|
17
|
+
Johnson.symbolCache = {};
|
18
|
+
|
19
|
+
Johnson.symbolize = function(string) {
|
20
|
+
if (!Johnson.symbolCache[string])
|
21
|
+
Johnson.symbolCache[string] = new Johnson.Symbol(string);
|
22
|
+
|
23
|
+
return Johnson.symbolCache[string];
|
24
|
+
};
|
25
|
+
|
26
|
+
Object.defineProperty(String.prototype, "toSymbol", function() {
|
27
|
+
return Johnson.symbolize(this.toString());
|
28
|
+
}, Object.READ_ONLY | Object.NON_DELETABLE);
|
29
|
+
|
30
|
+
Johnson.Generator = function(enumerableProxy) {
|
31
|
+
this.items = enumerableProxy.toArray();
|
32
|
+
this.index = 0;
|
33
|
+
};
|
34
|
+
|
35
|
+
Johnson.Generator.prototype.hasNext = function() {
|
36
|
+
var len = this.items.length;
|
37
|
+
if (typeof len != 'number') len = this.items.length();
|
38
|
+
return this.index < len;
|
39
|
+
}
|
40
|
+
|
41
|
+
Johnson.Generator.prototype.next = function() {
|
42
|
+
if (this.hasNext()) {
|
43
|
+
return this.items[this.index++];
|
44
|
+
}
|
45
|
+
throw StopIteration;
|
46
|
+
}
|
47
|
+
|
48
|
+
Johnson.Generator.create = function() {
|
49
|
+
return new Johnson.Generator(this);
|
50
|
+
}
|
51
|
+
|
52
|
+
Johnson.required = {};
|
53
|
+
|
54
|
+
Johnson.require = function(file) {
|
55
|
+
file = Ruby.File.join(Ruby.File.dirname(file),
|
56
|
+
Ruby.File.basename(file, ".js") + ".js");
|
57
|
+
|
58
|
+
if(Johnson.required[file]) return false;
|
59
|
+
|
60
|
+
for(var directory in Ruby["$LOAD_PATH"]) {
|
61
|
+
var path = Ruby.File.join(directory, file);
|
62
|
+
|
63
|
+
if(Ruby.File.send("file?", path)) {
|
64
|
+
Johnson.required[file] = true;
|
65
|
+
Johnson.runtime.load(path);
|
66
|
+
|
67
|
+
return true;
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
throw Ruby.LoadError;
|
72
|
+
}
|
73
|
+
|
74
|
+
this.__defineGetter__("__FILE__", function() {
|
75
|
+
try { throw new Error; } catch(e) {
|
76
|
+
return e.stack.split("\n")[2].split("@")[1].split(":").slice(0,-1).join(":");
|
77
|
+
}
|
78
|
+
})
|
79
|
+
|
80
|
+
null; // no need to marshal a result
|
@@ -0,0 +1,29 @@
|
|
1
|
+
Johnson.templatize = function (template, begin, end) {
|
2
|
+
var begin = begin || "<%"
|
3
|
+
var end = end || "%>"
|
4
|
+
var rebegin = begin.replace(/([\]{}[\\])/g, '\\$1');
|
5
|
+
var reend = end.replace(/([\]{}[\\])/g, '\\$1');
|
6
|
+
|
7
|
+
var code = "_context = _context || {}; with (_context) {" +
|
8
|
+
"var _result = '';" +
|
9
|
+
template
|
10
|
+
.replace(/[\t\r\n]/g, ' ')
|
11
|
+
.replace(/^(.*)$/, end + '$1' + begin)
|
12
|
+
.replace(new RegExp(reend + "(.*?)" + rebegin, "g"), function (text) {
|
13
|
+
return text
|
14
|
+
.replace(new RegExp("^" + reend + "(.*)" + rebegin + "$"), "$1")
|
15
|
+
.replace(/\\/g, "\\\\")
|
16
|
+
.replace(/'/g, "\\'")
|
17
|
+
.replace(/^(.*)$/,
|
18
|
+
function(sub, m) {
|
19
|
+
return end + (m == "" ? "" : "_result += '" + m + "';") + begin;
|
20
|
+
});
|
21
|
+
})
|
22
|
+
.replace(new RegExp(rebegin + "=(.*?)" + reend, "g"), "_result += ($1);")
|
23
|
+
.replace(new RegExp(rebegin + "(.*?)" + reend, "g"), ' $1 ')
|
24
|
+
.replace(new RegExp("^" + reend + "(.*)" + rebegin + "$"), '$1') +
|
25
|
+
"return _result;" +
|
26
|
+
"}";
|
27
|
+
|
28
|
+
return new Function("_context", code);
|
29
|
+
};
|
data/lib/hoe.rb
ADDED
@@ -0,0 +1,748 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
# Copyright (c) Ryan Davis, Zen Spider Software
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
# a copy of this software and associated documentation files (the
|
7
|
+
# "Software"), to deal in the Software without restriction, including
|
8
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
# the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be
|
14
|
+
# included in all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
20
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
21
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
22
|
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
require 'rubygems'
|
25
|
+
require 'rake'
|
26
|
+
require 'rake/gempackagetask'
|
27
|
+
require 'rake/rdoctask'
|
28
|
+
require 'rake/testtask'
|
29
|
+
require 'rbconfig'
|
30
|
+
require 'rubyforge'
|
31
|
+
require 'yaml'
|
32
|
+
|
33
|
+
class Hoe #:nodoc:
|
34
|
+
VERSION = '1.5.3'
|
35
|
+
|
36
|
+
ruby_prefix = Config::CONFIG['prefix']
|
37
|
+
sitelibdir = Config::CONFIG['sitelibdir']
|
38
|
+
|
39
|
+
##
|
40
|
+
# Used to specify a custom install location (for rake install).
|
41
|
+
|
42
|
+
PREFIX = ENV['PREFIX'] || ruby_prefix
|
43
|
+
|
44
|
+
##
|
45
|
+
# Used to add extra flags to RUBY_FLAGS.
|
46
|
+
|
47
|
+
RUBY_DEBUG = ENV['RUBY_DEBUG']
|
48
|
+
|
49
|
+
default_ruby_flags = "-w -I#{%w(lib ext bin test).join(File::PATH_SEPARATOR)}" +
|
50
|
+
(RUBY_DEBUG ? " #{RUBY_DEBUG}" : '')
|
51
|
+
|
52
|
+
##
|
53
|
+
# Used to specify flags to ruby [has smart default].
|
54
|
+
|
55
|
+
RUBY_FLAGS = ENV['RUBY_FLAGS'] || default_ruby_flags
|
56
|
+
|
57
|
+
##
|
58
|
+
# Used to add flags to test_unit (e.g., -n test_borked).
|
59
|
+
|
60
|
+
FILTER = ENV['FILTER'] # for tests (eg FILTER="-n test_blah")
|
61
|
+
|
62
|
+
# :stopdoc:
|
63
|
+
|
64
|
+
RUBYLIB = if PREFIX == ruby_prefix then
|
65
|
+
sitelibdir
|
66
|
+
else
|
67
|
+
File.join(PREFIX, sitelibdir[ruby_prefix.size..-1])
|
68
|
+
end
|
69
|
+
|
70
|
+
DLEXT = Config::CONFIG['DLEXT']
|
71
|
+
|
72
|
+
WINDOZE = /djgpp|(cyg|ms|bcc)win|mingw/ =~ RUBY_PLATFORM unless defined? WINDOZE
|
73
|
+
|
74
|
+
DIFF = if WINDOZE
|
75
|
+
'diff.exe'
|
76
|
+
else
|
77
|
+
if system("gdiff", __FILE__, __FILE__)
|
78
|
+
'gdiff' # solaris and kin suck
|
79
|
+
else
|
80
|
+
'diff'
|
81
|
+
end
|
82
|
+
end unless defined? DIFF
|
83
|
+
|
84
|
+
# :startdoc:
|
85
|
+
|
86
|
+
##
|
87
|
+
# *Recommended*: The author(s) of the package. (can be array)
|
88
|
+
# Really. Set this or we'll tease you.
|
89
|
+
|
90
|
+
attr_accessor :author
|
91
|
+
|
92
|
+
##
|
93
|
+
# Populated automatically from the manifest. List of executables.
|
94
|
+
|
95
|
+
attr_accessor :bin_files # :nodoc:
|
96
|
+
|
97
|
+
##
|
98
|
+
# Optional: A description of the release's latest changes. Auto-populates.
|
99
|
+
|
100
|
+
attr_accessor :changes
|
101
|
+
|
102
|
+
##
|
103
|
+
# Optional: An array of file patterns to delete on clean.
|
104
|
+
|
105
|
+
attr_accessor :clean_globs
|
106
|
+
|
107
|
+
##
|
108
|
+
# Optional: A description of the project. Auto-populates.
|
109
|
+
|
110
|
+
attr_accessor :description
|
111
|
+
|
112
|
+
##
|
113
|
+
# Optional: What sections from the readme to use for auto-description. Defaults to %w(description).
|
114
|
+
|
115
|
+
attr_accessor :description_sections
|
116
|
+
|
117
|
+
##
|
118
|
+
# *Recommended*: The author's email address(es). (can be array)
|
119
|
+
|
120
|
+
attr_accessor :email
|
121
|
+
|
122
|
+
##
|
123
|
+
# Optional: An array of rubygem dependencies.
|
124
|
+
|
125
|
+
attr_accessor :extra_deps
|
126
|
+
|
127
|
+
##
|
128
|
+
# Populated automatically from the manifest. List of library files.
|
129
|
+
|
130
|
+
attr_accessor :lib_files # :nodoc:
|
131
|
+
|
132
|
+
##
|
133
|
+
# Optional: Array of incompatible versions for multiruby filtering. Used as a regex.
|
134
|
+
|
135
|
+
attr_accessor :multiruby_skip
|
136
|
+
|
137
|
+
##
|
138
|
+
# *MANDATORY*: The name of the release.
|
139
|
+
|
140
|
+
attr_accessor :name
|
141
|
+
|
142
|
+
##
|
143
|
+
# Optional: Should package create a tarball? [default: true]
|
144
|
+
|
145
|
+
attr_accessor :need_tar
|
146
|
+
|
147
|
+
##
|
148
|
+
# Optional: Should package create a zipfile? [default: false]
|
149
|
+
|
150
|
+
attr_accessor :need_zip
|
151
|
+
|
152
|
+
##
|
153
|
+
# Optional: A post-install message to be displayed when gem is installed.
|
154
|
+
|
155
|
+
attr_accessor :post_install_message
|
156
|
+
|
157
|
+
##
|
158
|
+
# Optional: A regexp to match documentation files against the manifest.
|
159
|
+
|
160
|
+
attr_accessor :rdoc_pattern
|
161
|
+
|
162
|
+
##
|
163
|
+
# Optional: Name of RDoc destination directory on Rubyforge. [default: +name+]
|
164
|
+
|
165
|
+
attr_accessor :remote_rdoc_dir
|
166
|
+
|
167
|
+
##
|
168
|
+
# Optional: Flags for RDoc rsync. [default: "-av --delete"]
|
169
|
+
|
170
|
+
attr_accessor :rsync_args
|
171
|
+
|
172
|
+
##
|
173
|
+
# Optional: The name of the rubyforge project. [default: name.downcase]
|
174
|
+
|
175
|
+
attr_accessor :rubyforge_name
|
176
|
+
|
177
|
+
##
|
178
|
+
# The Gem::Specification.
|
179
|
+
|
180
|
+
attr_accessor :spec # :nodoc:
|
181
|
+
|
182
|
+
##
|
183
|
+
# Optional: A hash of extra values to set in the gemspec. Value may be a proc.
|
184
|
+
|
185
|
+
attr_accessor :spec_extras
|
186
|
+
|
187
|
+
##
|
188
|
+
# Optional: A short summary of the project. Auto-populates.
|
189
|
+
|
190
|
+
attr_accessor :summary
|
191
|
+
|
192
|
+
##
|
193
|
+
# Optional: Number of sentences from description for summary. Defaults to 1.
|
194
|
+
|
195
|
+
attr_accessor :summary_sentences
|
196
|
+
|
197
|
+
##
|
198
|
+
# Populated automatically from the manifest. List of tests.
|
199
|
+
|
200
|
+
attr_accessor :test_files # :nodoc:
|
201
|
+
|
202
|
+
##
|
203
|
+
# Optional: An array of test file patterns [default: test/**/test_*.rb]
|
204
|
+
|
205
|
+
attr_accessor :test_globs
|
206
|
+
|
207
|
+
##
|
208
|
+
# Optional: The url(s) of the project. (can be array). Auto-populates.
|
209
|
+
|
210
|
+
attr_accessor :url
|
211
|
+
|
212
|
+
##
|
213
|
+
# *MANDATORY*: The version. Don't hardcode! use a constant in the project.
|
214
|
+
|
215
|
+
attr_accessor :version
|
216
|
+
|
217
|
+
def initialize(name, version) # :nodoc:
|
218
|
+
self.name = name
|
219
|
+
self.version = version
|
220
|
+
|
221
|
+
# Defaults
|
222
|
+
self.author = []
|
223
|
+
self.clean_globs = %w(diff diff.txt email.txt ri
|
224
|
+
*.gem *~ **/*~ *.rbc **/*.rbc)
|
225
|
+
self.description_sections = %w(description)
|
226
|
+
self.email = []
|
227
|
+
self.extra_deps = []
|
228
|
+
self.multiruby_skip = []
|
229
|
+
self.need_tar = true
|
230
|
+
self.need_zip = false
|
231
|
+
self.rdoc_pattern = /^(lib|bin|ext)|(rdoc|txt)$/
|
232
|
+
self.remote_rdoc_dir = name
|
233
|
+
self.rsync_args = '-av --delete'
|
234
|
+
self.rubyforge_name = name.downcase
|
235
|
+
self.spec_extras = {}
|
236
|
+
self.summary_sentences = 1
|
237
|
+
self.test_globs = ['test/**/test_*.rb']
|
238
|
+
self.post_install_message = nil
|
239
|
+
|
240
|
+
yield self if block_given?
|
241
|
+
|
242
|
+
# Intuit values:
|
243
|
+
|
244
|
+
def missing name
|
245
|
+
warn "** #{name} is missing or in the wrong format for auto-intuiting."
|
246
|
+
warn " run `sow blah` and look at its text files"
|
247
|
+
end
|
248
|
+
|
249
|
+
readme = File.read("README.rdoc").split(/^(=+ .*)$/)[1..-1] rescue ''
|
250
|
+
unless readme.empty? then
|
251
|
+
sections = readme.map { |s|
|
252
|
+
s =~ /^=/ ? s.strip.downcase.chomp(':').split.last : s.strip
|
253
|
+
}
|
254
|
+
sections = Hash[*sections]
|
255
|
+
desc = sections.values_at(*description_sections).join("\n\n")
|
256
|
+
summ = desc.split(/\.\s+/).first(summary_sentences).join(". ")
|
257
|
+
|
258
|
+
self.description ||= desc
|
259
|
+
self.summary ||= summ
|
260
|
+
self.url ||= readme[1].gsub(/^\* /, '').split(/\n/).grep(/\S+/)
|
261
|
+
else
|
262
|
+
missing 'README.rdoc'
|
263
|
+
end
|
264
|
+
|
265
|
+
self.changes ||= begin
|
266
|
+
h = File.read("CHANGELOG")
|
267
|
+
h.split(/^(===.*)/)[1..2].join.strip
|
268
|
+
rescue
|
269
|
+
missing 'CHANGELOG'
|
270
|
+
''
|
271
|
+
end
|
272
|
+
|
273
|
+
%w(email author).each do |field|
|
274
|
+
value = self.send(field)
|
275
|
+
if value.nil? or value.empty? then
|
276
|
+
if Time.now < Time.local(2008, 4, 1) then
|
277
|
+
warn "Hoe #{field} value not set - Fix by 2008-04-01!"
|
278
|
+
self.send "#{field}=", "doofus"
|
279
|
+
else
|
280
|
+
abort "Hoe #{field} value not set. aborting"
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
self.extra_deps = Array(extra_deps).map { |o| String === o ? [o] : o }
|
286
|
+
|
287
|
+
define_tasks
|
288
|
+
end
|
289
|
+
|
290
|
+
def developer name, email
|
291
|
+
self.author << name
|
292
|
+
self.email << email
|
293
|
+
end
|
294
|
+
|
295
|
+
def define_tasks # :nodoc:
|
296
|
+
def with_config # :nodoc:
|
297
|
+
rc = File.expand_path("~/.hoerc")
|
298
|
+
exists = File.exist? rc
|
299
|
+
config = exists ? YAML.load_file(rc) : {}
|
300
|
+
yield(config, rc)
|
301
|
+
end
|
302
|
+
|
303
|
+
desc 'Run the default tasks.'
|
304
|
+
task :default => :test
|
305
|
+
|
306
|
+
desc 'Run the test suite. Use FILTER to add to the command line.'
|
307
|
+
task :test do
|
308
|
+
run_tests
|
309
|
+
end
|
310
|
+
|
311
|
+
desc 'Show which test files fail when run alone.'
|
312
|
+
task :test_deps do
|
313
|
+
tests = Dir["test/**/test_*.rb"] + Dir["test/**/*_test.rb"]
|
314
|
+
|
315
|
+
tests.each do |test|
|
316
|
+
if not system "ruby -Ibin:lib:test #{test} &> /dev/null" then
|
317
|
+
puts "Dependency Issues: #{test}"
|
318
|
+
end
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
desc 'Run the test suite using multiruby.'
|
323
|
+
task :multi do
|
324
|
+
run_tests :multi
|
325
|
+
end
|
326
|
+
|
327
|
+
############################################################
|
328
|
+
# Packaging and Installing
|
329
|
+
|
330
|
+
signing_key = nil
|
331
|
+
cert_chain = []
|
332
|
+
|
333
|
+
with_config do |config, path|
|
334
|
+
break unless config['signing_key_file'] and config['signing_cert_file']
|
335
|
+
key_file = File.expand_path config['signing_key_file'].to_s
|
336
|
+
signing_key = key_file if File.exist? key_file
|
337
|
+
|
338
|
+
cert_file = File.expand_path config['signing_cert_file'].to_s
|
339
|
+
cert_chain << cert_file if File.exist? cert_file
|
340
|
+
end
|
341
|
+
|
342
|
+
self.spec = Gem::Specification.new do |s|
|
343
|
+
s.name = name
|
344
|
+
s.version = version
|
345
|
+
s.summary = summary
|
346
|
+
case author
|
347
|
+
when Array
|
348
|
+
s.authors = author
|
349
|
+
else
|
350
|
+
s.author = author
|
351
|
+
end
|
352
|
+
s.email = email
|
353
|
+
s.homepage = Array(url).first
|
354
|
+
s.rubyforge_project = rubyforge_name
|
355
|
+
|
356
|
+
s.description = description
|
357
|
+
|
358
|
+
extra_deps.each do |dep|
|
359
|
+
s.add_dependency(*dep)
|
360
|
+
end
|
361
|
+
|
362
|
+
s.files = File.read("MANIFEST").delete("\r").split(/\n/)
|
363
|
+
s.executables = s.files.grep(/^bin/) { |f| File.basename(f) }
|
364
|
+
|
365
|
+
s.bindir = "bin"
|
366
|
+
dirs = Dir['{lib,ext}']
|
367
|
+
s.require_paths = dirs unless dirs.empty?
|
368
|
+
|
369
|
+
s.rdoc_options = ['--main', 'README.rdoc']
|
370
|
+
s.extra_rdoc_files = s.files.grep(/(txt|rdoc)$/)
|
371
|
+
s.has_rdoc = true
|
372
|
+
|
373
|
+
s.post_install_message = post_install_message
|
374
|
+
|
375
|
+
if test ?f, "test/test_all.rb" then
|
376
|
+
s.test_file = "test/test_all.rb"
|
377
|
+
else
|
378
|
+
s.test_files = Dir[*test_globs]
|
379
|
+
end
|
380
|
+
|
381
|
+
if signing_key and cert_chain then
|
382
|
+
s.signing_key = signing_key
|
383
|
+
s.cert_chain = cert_chain
|
384
|
+
end
|
385
|
+
|
386
|
+
############################################################
|
387
|
+
# Allow automatic inclusion of compiled extensions
|
388
|
+
if ENV['INLINE'] then
|
389
|
+
s.platform = ENV['FORCE_PLATFORM'] || Gem::Platform::CURRENT
|
390
|
+
# name of the extension is CamelCase
|
391
|
+
alternate_name = if name =~ /[A-Z]/ then
|
392
|
+
name.gsub(/([A-Z])/, '_\1').downcase.sub(/^_/, '')
|
393
|
+
elsif name =~ /_/ then
|
394
|
+
name.capitalize.gsub(/_([a-z])/) { $1.upcase }
|
395
|
+
end
|
396
|
+
|
397
|
+
# Try collecting Inline extensions for +name+
|
398
|
+
if defined?(Inline) then
|
399
|
+
directory 'lib/inline'
|
400
|
+
|
401
|
+
extensions = Dir.chdir(Inline::directory) {
|
402
|
+
Dir["Inline_{#{name},#{alternate_name}}_*.#{DLEXT}"]
|
403
|
+
}
|
404
|
+
extensions.each do |ext|
|
405
|
+
# add the inlined extension to the spec files
|
406
|
+
s.files += ["lib/inline/#{ext}"]
|
407
|
+
|
408
|
+
# include the file in the tasks
|
409
|
+
file "lib/inline/#{ext}" => ["lib/inline"] do
|
410
|
+
cp File.join(Inline::directory, ext), "lib/inline"
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
# Do any extra stuff the user wants
|
417
|
+
spec_extras.each do |msg, val|
|
418
|
+
case val
|
419
|
+
when Proc
|
420
|
+
val.call(s.send(msg))
|
421
|
+
else
|
422
|
+
s.send "#{msg}=", val
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
desc 'Show information about the gem.'
|
428
|
+
task :debug_gem do
|
429
|
+
puts spec.to_ruby
|
430
|
+
end
|
431
|
+
|
432
|
+
desc "Generate #{name}.gemspec"
|
433
|
+
task :gemspec do
|
434
|
+
File.open("#{name}.gemspec", "w") do |f|
|
435
|
+
f.write spec.to_ruby
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
self.lib_files = spec.files.grep(/^(lib|ext)/)
|
440
|
+
self.bin_files = spec.files.grep(/^bin/)
|
441
|
+
self.test_files = spec.files.grep(/^test/)
|
442
|
+
|
443
|
+
Rake::GemPackageTask.new spec do |pkg|
|
444
|
+
pkg.need_tar = @need_tar
|
445
|
+
pkg.need_zip = @need_zip
|
446
|
+
end
|
447
|
+
|
448
|
+
desc 'Install the package as a gem.'
|
449
|
+
task :install_gem => [:clean, :package] do
|
450
|
+
sh "#{'sudo ' unless WINDOZE}gem install --local pkg/*.gem"
|
451
|
+
end
|
452
|
+
|
453
|
+
desc 'Package and upload the release to rubyforge.'
|
454
|
+
task :release => [:clean, :package] do |t|
|
455
|
+
v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z"
|
456
|
+
abort "Versions don't match #{v} vs #{version}" if v != version
|
457
|
+
pkg = "pkg/#{name}-#{version}"
|
458
|
+
|
459
|
+
if $DEBUG then
|
460
|
+
puts "release_id = rf.add_release #{rubyforge_name.inspect}, #{name.inspect}, #{version.inspect}, \"#{pkg}.tgz\""
|
461
|
+
puts "rf.add_file #{rubyforge_name.inspect}, #{name.inspect}, release_id, \"#{pkg}.gem\""
|
462
|
+
end
|
463
|
+
|
464
|
+
rf = RubyForge.new.configure
|
465
|
+
puts "Logging in"
|
466
|
+
rf.login
|
467
|
+
|
468
|
+
c = rf.userconfig
|
469
|
+
c["release_notes"] = description if description
|
470
|
+
c["release_changes"] = changes if changes
|
471
|
+
c["preformatted"] = true
|
472
|
+
|
473
|
+
files = [(@need_tar ? "#{pkg}.tgz" : nil),
|
474
|
+
(@need_zip ? "#{pkg}.zip" : nil),
|
475
|
+
"#{pkg}.gem"].compact
|
476
|
+
|
477
|
+
puts "Releasing #{name} v. #{version}"
|
478
|
+
rf.add_release rubyforge_name, name, version, *files
|
479
|
+
end
|
480
|
+
|
481
|
+
############################################################
|
482
|
+
# Doco
|
483
|
+
|
484
|
+
Rake::RDocTask.new(:docs) do |rd|
|
485
|
+
rd.main = "README.rdoc"
|
486
|
+
rd.options << '-d' if RUBY_PLATFORM !~ /win32/ and `which dot` =~ /\/dot/ and not ENV['NODOT']
|
487
|
+
rd.rdoc_dir = 'doc'
|
488
|
+
files = spec.files.grep(rdoc_pattern)
|
489
|
+
files -= ['MANIFEST', 'lib/hoe.rb']
|
490
|
+
rd.rdoc_files.push(*files)
|
491
|
+
|
492
|
+
title = "#{name}-#{version} Documentation"
|
493
|
+
title = "#{rubyforge_name}'s " + title if rubyforge_name != name
|
494
|
+
|
495
|
+
rd.options << "-t #{title}"
|
496
|
+
end
|
497
|
+
|
498
|
+
desc 'Generate ri locally for testing.'
|
499
|
+
task :ridocs => :clean do
|
500
|
+
sh %q{ rdoc --ri -o ri . }
|
501
|
+
end
|
502
|
+
|
503
|
+
desc 'Publish RDoc to RubyForge.'
|
504
|
+
task :publish_docs => [:clean, :docs] do
|
505
|
+
config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
|
506
|
+
host = "#{config["username"]}@rubyforge.org"
|
507
|
+
|
508
|
+
remote_dir = "/var/www/gforge-projects/#{rubyforge_name}/#{remote_rdoc_dir}"
|
509
|
+
local_dir = 'doc'
|
510
|
+
|
511
|
+
sh %{rsync #{rsync_args} #{local_dir}/ #{host}:#{remote_dir}}
|
512
|
+
end
|
513
|
+
|
514
|
+
# no doco for this one
|
515
|
+
task :publish_on_announce do
|
516
|
+
with_config do |config, _|
|
517
|
+
Rake::Task['publish_docs'].invoke if config["publish_on_announce"]
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
############################################################
|
522
|
+
# Misc/Maintenance:
|
523
|
+
|
524
|
+
desc 'Run ZenTest against the package.'
|
525
|
+
task :audit do
|
526
|
+
libs = %w(lib test ext).join(File::PATH_SEPARATOR)
|
527
|
+
sh "zentest -I=#{libs} #{spec.files.grep(/^(lib|test)/).join(' ')}"
|
528
|
+
end
|
529
|
+
|
530
|
+
desc 'Clean up all the extras.'
|
531
|
+
task :clean => [ :clobber_docs, :clobber_package ] do
|
532
|
+
clean_globs.each do |pattern|
|
533
|
+
files = Dir[pattern]
|
534
|
+
rm_rf files, :verbose => true unless files.empty?
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
desc 'Create a fresh ~/.hoerc file.'
|
539
|
+
task :config_hoe do
|
540
|
+
with_config do |config, path|
|
541
|
+
default_config = {
|
542
|
+
"exclude" => /tmp$|CVS|\.svn/,
|
543
|
+
"publish_on_announce" => false,
|
544
|
+
"signing_key_file" => "~/.gem/gem-private_key.pem",
|
545
|
+
"signing_cert_file" => "~/.gem/gem-public_cert.pem",
|
546
|
+
"blogs" => [ {
|
547
|
+
"user" => "user",
|
548
|
+
"url" => "url",
|
549
|
+
"extra_headers" => {
|
550
|
+
"mt_convert_breaks" => "markdown"
|
551
|
+
},
|
552
|
+
"blog_id" => "blog_id",
|
553
|
+
"password"=>"password",
|
554
|
+
} ],
|
555
|
+
}
|
556
|
+
File.open(path, "w") do |f|
|
557
|
+
YAML.dump(default_config.merge(config), f)
|
558
|
+
end
|
559
|
+
|
560
|
+
editor = ENV['EDITOR'] || 'vi'
|
561
|
+
system "#{editor} #{path}" if ENV['SHOW_EDITOR'] != 'no'
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
565
|
+
desc 'Generate email announcement file.'
|
566
|
+
task :email do
|
567
|
+
require 'rubyforge'
|
568
|
+
subject, title, body, urls = announcement
|
569
|
+
|
570
|
+
File.open("email.txt", "w") do |mail|
|
571
|
+
mail.puts "Subject: [ANN] #{subject}"
|
572
|
+
mail.puts
|
573
|
+
mail.puts title
|
574
|
+
mail.puts
|
575
|
+
mail.puts urls
|
576
|
+
mail.puts
|
577
|
+
mail.puts body
|
578
|
+
mail.puts
|
579
|
+
mail.puts urls
|
580
|
+
end
|
581
|
+
puts "Created email.txt"
|
582
|
+
end
|
583
|
+
|
584
|
+
desc 'Post announcement to blog.'
|
585
|
+
task :post_blog do
|
586
|
+
require 'xmlrpc/client'
|
587
|
+
|
588
|
+
with_config do |config, path|
|
589
|
+
break unless config['blogs']
|
590
|
+
|
591
|
+
subject, title, body, urls = announcement
|
592
|
+
body += "\n\n#{urls}"
|
593
|
+
|
594
|
+
config['blogs'].each do |site|
|
595
|
+
server = XMLRPC::Client.new2(site['url'])
|
596
|
+
content = site['extra_headers'].merge(:title => title,
|
597
|
+
:description => body)
|
598
|
+
result = server.call('metaWeblog.newPost',
|
599
|
+
site['blog_id'],
|
600
|
+
site['user'],
|
601
|
+
site['password'],
|
602
|
+
content,
|
603
|
+
true)
|
604
|
+
end
|
605
|
+
end
|
606
|
+
end
|
607
|
+
|
608
|
+
desc 'Post announcement to rubyforge.'
|
609
|
+
task :post_news do
|
610
|
+
require 'rubyforge'
|
611
|
+
subject, title, body, urls = announcement
|
612
|
+
|
613
|
+
rf = RubyForge.new.configure
|
614
|
+
rf.login
|
615
|
+
rf.post_news(rubyforge_name, subject, "#{title}\n\n#{body}")
|
616
|
+
puts "Posted to rubyforge"
|
617
|
+
end
|
618
|
+
|
619
|
+
desc 'Create news email file and post to rubyforge.'
|
620
|
+
task :announce => [:email, :post_news, :post_blog, :publish_on_announce ]
|
621
|
+
|
622
|
+
desc 'Verify the manifest.'
|
623
|
+
task :check_manifest => :clean do
|
624
|
+
f = "Manifest.tmp"
|
625
|
+
require 'find'
|
626
|
+
files = []
|
627
|
+
with_config do |config, _|
|
628
|
+
exclusions = config["exclude"]
|
629
|
+
abort "exclude entry missing from .hoerc. Aborting." if exclusions.nil?
|
630
|
+
Find.find '.' do |path|
|
631
|
+
next unless File.file? path
|
632
|
+
next if path =~ exclusions
|
633
|
+
files << path[2..-1]
|
634
|
+
end
|
635
|
+
files = files.sort.join "\n"
|
636
|
+
File.open f, 'w' do |fp| fp.puts files end
|
637
|
+
system "#{DIFF} -du MANIFEST #{f}"
|
638
|
+
rm f
|
639
|
+
end
|
640
|
+
end
|
641
|
+
|
642
|
+
desc 'Generate a key for signing your gems.'
|
643
|
+
task :generate_key do
|
644
|
+
email = spec.email
|
645
|
+
abort "No email in your gemspec" if email.nil? or email.empty?
|
646
|
+
|
647
|
+
key_file = with_config { |config, _| config['signing_key_file'] }
|
648
|
+
cert_file = with_config { |config, _| config['signing_cert_file'] }
|
649
|
+
|
650
|
+
if key_file.nil? or cert_file.nil? then
|
651
|
+
ENV['SHOW_EDITOR'] ||= 'no'
|
652
|
+
Rake::Task['config_hoe'].invoke
|
653
|
+
|
654
|
+
key_file = with_config { |config, _| config['signing_key_file'] }
|
655
|
+
cert_file = with_config { |config, _| config['signing_cert_file'] }
|
656
|
+
end
|
657
|
+
|
658
|
+
key_file = File.expand_path key_file
|
659
|
+
cert_file = File.expand_path cert_file
|
660
|
+
|
661
|
+
unless File.exist? key_file or File.exist? cert_file then
|
662
|
+
sh "gem cert --build #{email}"
|
663
|
+
mv "gem-private_key.pem", key_file, :verbose => true
|
664
|
+
mv "gem-public_cert.pem", cert_file, :verbose => true
|
665
|
+
|
666
|
+
puts "Installed key and certificate."
|
667
|
+
|
668
|
+
rf = RubyForge.new.configure
|
669
|
+
rf.login
|
670
|
+
|
671
|
+
cert_package = "#{rubyforge_name}-certificates"
|
672
|
+
|
673
|
+
begin
|
674
|
+
rf.lookup 'package', cert_package
|
675
|
+
rescue
|
676
|
+
rf.create_package rubyforge_name, cert_package
|
677
|
+
end
|
678
|
+
|
679
|
+
begin
|
680
|
+
rf.lookup('release', cert_package)['certificates']
|
681
|
+
rf.add_file rubyforge_name, cert_package, 'certificates', cert_file
|
682
|
+
rescue
|
683
|
+
rf.add_release rubyforge_name, cert_package, 'certificates', cert_file
|
684
|
+
end
|
685
|
+
|
686
|
+
puts "Uploaded certificate to release \"certificates\" in package #{cert_package}"
|
687
|
+
else
|
688
|
+
puts "Keys already exist."
|
689
|
+
end
|
690
|
+
end
|
691
|
+
|
692
|
+
end # end define
|
693
|
+
|
694
|
+
def announcement # :nodoc:
|
695
|
+
changes = self.changes.rdoc_to_markdown
|
696
|
+
|
697
|
+
subject = "#{name} #{version} Released"
|
698
|
+
title = "#{name} version #{version} has been released!"
|
699
|
+
body = "#{description}\n\nChanges:\n\n#{changes}".rdoc_to_markdown
|
700
|
+
urls = Array(url).map { |s| "* <#{s.strip.rdoc_to_markdown}>" }.join("\n")
|
701
|
+
|
702
|
+
return subject, title, body, urls
|
703
|
+
end
|
704
|
+
|
705
|
+
def run_tests(multi=false) # :nodoc:
|
706
|
+
msg = multi ? :sh : :ruby
|
707
|
+
cmd = if test ?f, 'test/test_all.rb' then
|
708
|
+
"#{RUBY_FLAGS} test/test_all.rb #{FILTER}"
|
709
|
+
else
|
710
|
+
tests = ['test/unit'] + test_globs.map { |g| Dir.glob(g) }.flatten
|
711
|
+
tests.map! {|f| %Q(require "#{f}")}
|
712
|
+
"#{RUBY_FLAGS} -e '#{tests.join("; ")}' #{FILTER}"
|
713
|
+
end
|
714
|
+
|
715
|
+
excludes = multiruby_skip.join(":")
|
716
|
+
ENV['EXCLUDED_VERSIONS'] = excludes
|
717
|
+
cmd = "multiruby #{cmd}" if multi
|
718
|
+
|
719
|
+
send msg, cmd
|
720
|
+
end
|
721
|
+
|
722
|
+
##
|
723
|
+
# Reads a file at +path+ and spits out an array of the +paragraphs+ specified.
|
724
|
+
#
|
725
|
+
# changes = p.paragraphs_of('CHANGELOG', 0..1).join("\n\n")
|
726
|
+
# summary, *description = p.paragraphs_of('README.rdoc', 3, 3..8)
|
727
|
+
|
728
|
+
def paragraphs_of(path, *paragraphs)
|
729
|
+
File.read(path).delete("\r").split(/\n\n+/).values_at(*paragraphs)
|
730
|
+
end
|
731
|
+
end
|
732
|
+
|
733
|
+
# :enddoc:
|
734
|
+
|
735
|
+
class ::Rake::SshDirPublisher # :nodoc:
|
736
|
+
attr_reader :host, :remote_dir, :local_dir
|
737
|
+
end
|
738
|
+
|
739
|
+
class String
|
740
|
+
def rdoc_to_markdown
|
741
|
+
self.gsub(/^mailto:/, '').gsub(/^(=+)/) { "#" * $1.size }
|
742
|
+
end
|
743
|
+
end
|
744
|
+
|
745
|
+
if $0 == __FILE__ then
|
746
|
+
out = `rake -T | egrep -v "redocs|repackage|clobber|trunk"`
|
747
|
+
puts out.gsub(/\#/, '-').gsub(/^rake /, '# * ')
|
748
|
+
end
|