walidhalabi-celerity 0.0.6.11
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/History.txt +75 -0
- data/License.txt +621 -0
- data/README.txt +73 -0
- data/Rakefile +12 -0
- data/lib/celerity.rb +74 -0
- data/lib/celerity/browser.rb +811 -0
- data/lib/celerity/clickable_element.rb +69 -0
- data/lib/celerity/collections.rb +156 -0
- data/lib/celerity/container.rb +788 -0
- data/lib/celerity/default_viewer.rb +10 -0
- data/lib/celerity/disabled_element.rb +40 -0
- data/lib/celerity/element.rb +313 -0
- data/lib/celerity/element_collection.rb +107 -0
- data/lib/celerity/element_locator.rb +170 -0
- data/lib/celerity/elements/button.rb +43 -0
- data/lib/celerity/elements/file_field.rb +25 -0
- data/lib/celerity/elements/form.rb +23 -0
- data/lib/celerity/elements/frame.rb +75 -0
- data/lib/celerity/elements/image.rb +76 -0
- data/lib/celerity/elements/label.rb +11 -0
- data/lib/celerity/elements/link.rb +30 -0
- data/lib/celerity/elements/meta.rb +6 -0
- data/lib/celerity/elements/non_control_elements.rb +106 -0
- data/lib/celerity/elements/option.rb +32 -0
- data/lib/celerity/elements/radio_check.rb +115 -0
- data/lib/celerity/elements/select_list.rb +121 -0
- data/lib/celerity/elements/table.rb +144 -0
- data/lib/celerity/elements/table_cell.rb +29 -0
- data/lib/celerity/elements/table_elements.rb +42 -0
- data/lib/celerity/elements/table_row.rb +48 -0
- data/lib/celerity/elements/text_field.rb +169 -0
- data/lib/celerity/exception.rb +77 -0
- data/lib/celerity/htmlunit.rb +61 -0
- data/lib/celerity/htmlunit/commons-codec-1.3.jar +0 -0
- data/lib/celerity/htmlunit/commons-collections-3.2.1.jar +0 -0
- data/lib/celerity/htmlunit/commons-httpclient-3.1.jar +0 -0
- data/lib/celerity/htmlunit/commons-io-1.4.jar +0 -0
- data/lib/celerity/htmlunit/commons-lang-2.4.jar +0 -0
- data/lib/celerity/htmlunit/commons-logging-1.1.1.jar +0 -0
- data/lib/celerity/htmlunit/cssparser-0.9.5.jar +0 -0
- data/lib/celerity/htmlunit/htmlunit-2.6-SNAPSHOT.jar +0 -0
- data/lib/celerity/htmlunit/htmlunit-core-js-2.5.jar +0 -0
- data/lib/celerity/htmlunit/nekohtml-1.9.13-20090507.082850-2.jar +0 -0
- data/lib/celerity/htmlunit/sac-1.3.jar +0 -0
- data/lib/celerity/htmlunit/serializer-2.7.1.jar +0 -0
- data/lib/celerity/htmlunit/xalan-2.7.1.jar +0 -0
- data/lib/celerity/htmlunit/xercesImpl-2.8.1.jar +0 -0
- data/lib/celerity/htmlunit/xml-apis-1.3.04.jar +0 -0
- data/lib/celerity/identifier.rb +11 -0
- data/lib/celerity/input_element.rb +25 -0
- data/lib/celerity/listener.rb +141 -0
- data/lib/celerity/resources/no_viewer.png +0 -0
- data/lib/celerity/short_inspect.rb +20 -0
- data/lib/celerity/util.rb +91 -0
- data/lib/celerity/version.rb +10 -0
- data/lib/celerity/watir_compatibility.rb +84 -0
- data/tasks/jar.rake +57 -0
- data/tasks/rdoc.rake +4 -0
- metadata +130 -0
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Celerity
|
2
|
+
class InputElement < Element
|
3
|
+
include ClickableElement
|
4
|
+
include DisabledElement
|
5
|
+
|
6
|
+
ATTRIBUTES = BASE_ATTRIBUTES | [:type, :name, :value, :checked, :disabled, :readonly, :size, :maxlength,
|
7
|
+
:src, :alt, :usemap, :ismap, :tabindex, :accesskey, :onfocus, :onblur,
|
8
|
+
:onselect, :onchange, :accept, :align]
|
9
|
+
|
10
|
+
def readonly?
|
11
|
+
assert_exists
|
12
|
+
@object.hasAttribute 'readonly'
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def assert_not_readonly
|
18
|
+
if readonly?
|
19
|
+
raise ObjectReadOnlyException,
|
20
|
+
"InputElement #{identifier_string} is read only."
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module Celerity
|
2
|
+
|
3
|
+
#
|
4
|
+
# This class is used to wrap some of the listeners available from HtmlUnit's WebClient.
|
5
|
+
#
|
6
|
+
|
7
|
+
class Listener
|
8
|
+
include com.gargoylesoftware.htmlunit.AlertHandler
|
9
|
+
include com.gargoylesoftware.htmlunit.ConfirmHandler
|
10
|
+
include com.gargoylesoftware.htmlunit.PromptHandler
|
11
|
+
include com.gargoylesoftware.htmlunit.html.HTMLParserListener
|
12
|
+
include com.gargoylesoftware.htmlunit.IncorrectnessListener
|
13
|
+
include com.gargoylesoftware.htmlunit.StatusHandler
|
14
|
+
include com.gargoylesoftware.htmlunit.WebWindowListener
|
15
|
+
include com.gargoylesoftware.htmlunit.attachment.AttachmentHandler
|
16
|
+
|
17
|
+
def initialize(webclient)
|
18
|
+
@webclient = webclient
|
19
|
+
@procs = Hash.new { |h, k| h[k] = [] }
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Add a listener block for one of the available types.
|
24
|
+
# @see Celerity::Browser#add_listener
|
25
|
+
#
|
26
|
+
|
27
|
+
def add_listener(type, &block)
|
28
|
+
case type
|
29
|
+
when :status
|
30
|
+
@webclient.setStatusHandler(self)
|
31
|
+
when :alert
|
32
|
+
@webclient.setAlertHandler(self)
|
33
|
+
when :attachment
|
34
|
+
@webclient.setAttachmentHandler(self)
|
35
|
+
when :web_window_event
|
36
|
+
@webclient.addWebWindowListener(self)
|
37
|
+
when :html_parser
|
38
|
+
@webclient.setHTMLParserListener(self)
|
39
|
+
when :incorrectness
|
40
|
+
@webclient.setIncorrectnessListener(self)
|
41
|
+
when :confirm
|
42
|
+
@webclient.setConfirmHandler(self)
|
43
|
+
when :prompt
|
44
|
+
@webclient.setPromptHandler(self)
|
45
|
+
else
|
46
|
+
raise ArgumentError, "unknown listener type #{type.inspect}"
|
47
|
+
end
|
48
|
+
|
49
|
+
@procs[type] << block
|
50
|
+
end
|
51
|
+
|
52
|
+
def remove_listener(type, proc_or_index)
|
53
|
+
unless @procs.has_key?(type)
|
54
|
+
raise ArgumentError, "unknown listener type #{type.inspect}"
|
55
|
+
end
|
56
|
+
|
57
|
+
case proc_or_index
|
58
|
+
when Fixnum
|
59
|
+
@procs[type].delete_at proc_or_index
|
60
|
+
when Proc
|
61
|
+
@procs[type].delete proc_or_index
|
62
|
+
else
|
63
|
+
raise TypeError, "must give proc or index"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# interface StatusHandler
|
69
|
+
#
|
70
|
+
|
71
|
+
def statusMessageChanged(page, message)
|
72
|
+
@procs[:status].each { |h| h.call(page, message) }
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# interface AlertHandler
|
77
|
+
#
|
78
|
+
|
79
|
+
def handleAlert(page, message)
|
80
|
+
@procs[:alert].each { |h| h.call(page, message) }
|
81
|
+
end
|
82
|
+
|
83
|
+
#
|
84
|
+
# interface ConfirmHandler
|
85
|
+
#
|
86
|
+
# The returned value is determined by the last registered :confirm listener proc.
|
87
|
+
# If it is nil, return true, otherwise return that value as a boolean.
|
88
|
+
#
|
89
|
+
# @see Browser#confirm
|
90
|
+
#
|
91
|
+
|
92
|
+
def handleConfirm(page, message)
|
93
|
+
val = @procs[:confirm].map { |h| h.call(page, message) }.last
|
94
|
+
val.nil? || !!val
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
# interface AttachmentHandler
|
99
|
+
#
|
100
|
+
|
101
|
+
def handleAttachment(page)
|
102
|
+
@procs[:attachment].each { |h| h.call(page) }
|
103
|
+
end
|
104
|
+
|
105
|
+
#
|
106
|
+
# interface PromptHandler
|
107
|
+
#
|
108
|
+
|
109
|
+
def handlePrompt(page, message)
|
110
|
+
@procs[:prompt].each { |h| h.call(page, message) }
|
111
|
+
end
|
112
|
+
|
113
|
+
#
|
114
|
+
# interface WebWindowListener
|
115
|
+
#
|
116
|
+
|
117
|
+
def webWindowClosed(web_window_event)
|
118
|
+
@procs[:web_window_event].each { |h| h.call(web_window_event) }
|
119
|
+
end
|
120
|
+
alias_method :webWindowOpened, :webWindowClosed
|
121
|
+
alias_method :webWindowContentChanged, :webWindowClosed
|
122
|
+
|
123
|
+
#
|
124
|
+
# interface HTMLParserListener
|
125
|
+
#
|
126
|
+
|
127
|
+
def error(message, url, line, column, key)
|
128
|
+
@procs[:html_parser].each { |h| h.call(message, url, line, column, key) }
|
129
|
+
end
|
130
|
+
alias_method :warning, :error
|
131
|
+
|
132
|
+
#
|
133
|
+
# interface IncorrectnessListener
|
134
|
+
#
|
135
|
+
|
136
|
+
def notify(message, origin)
|
137
|
+
@procs[:incorrectness].each { |h| h.call(message, origin) }
|
138
|
+
end
|
139
|
+
|
140
|
+
end # Listener
|
141
|
+
end # Celerity
|
Binary file
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Celerity
|
2
|
+
module ShortInspect
|
3
|
+
|
4
|
+
def short_inspect(opts)
|
5
|
+
if excluded_ivars = opts[:exclude]
|
6
|
+
ivars = (instance_variables - excluded_ivars)
|
7
|
+
elsif included_ivars = opts[:include]
|
8
|
+
ivars = included_ivars
|
9
|
+
else
|
10
|
+
raise ArgumentError, "unknown arg: #{opts.inspect}"
|
11
|
+
end
|
12
|
+
|
13
|
+
ivars.map! { |ivar| "#{ivar}=#{instance_variable_get(ivar).inspect}" }
|
14
|
+
'#<%s:0x%s %s>' % [self.class.name, self.hash.to_s(16), ivars.join(" ")]
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Celerity
|
2
|
+
module Util
|
3
|
+
module_function
|
4
|
+
|
5
|
+
HtmlUnit2CelerityElement = {
|
6
|
+
HtmlUnit::Html::HtmlAnchor => Celerity::Link,
|
7
|
+
HtmlUnit::Html::HtmlArea => Celerity::Area,
|
8
|
+
HtmlUnit::Html::HtmlButton => Celerity::Button,
|
9
|
+
HtmlUnit::Html::HtmlSubmitInput => Celerity::Button,
|
10
|
+
HtmlUnit::Html::HtmlResetInput => Celerity::Button,
|
11
|
+
HtmlUnit::Html::HtmlImageInput => Celerity::Button,
|
12
|
+
HtmlUnit::Html::HtmlButtonInput => Celerity::Button,
|
13
|
+
HtmlUnit::Html::HtmlCaption => Celerity::Button, # ?
|
14
|
+
HtmlUnit::Html::HtmlCheckBoxInput => Celerity::CheckBox,
|
15
|
+
HtmlUnit::Html::HtmlDefinitionDescription => Celerity::Dd,
|
16
|
+
HtmlUnit::Html::HtmlDefinitionList => Celerity::Dl,
|
17
|
+
HtmlUnit::Html::HtmlDefinitionTerm => Celerity::Dt,
|
18
|
+
HtmlUnit::Html::HtmlDivision => Celerity::Div,
|
19
|
+
HtmlUnit::Html::HtmlFileInput => Celerity::FileField,
|
20
|
+
HtmlUnit::Html::HtmlForm => Celerity::Form,
|
21
|
+
HtmlUnit::Html::HtmlFrame => Celerity::Frame,
|
22
|
+
HtmlUnit::Html::HtmlHeading1 => Celerity::H1,
|
23
|
+
HtmlUnit::Html::HtmlHeading2 => Celerity::H2,
|
24
|
+
HtmlUnit::Html::HtmlHeading3 => Celerity::H3,
|
25
|
+
HtmlUnit::Html::HtmlHeading4 => Celerity::H4,
|
26
|
+
HtmlUnit::Html::HtmlHeading5 => Celerity::H5,
|
27
|
+
HtmlUnit::Html::HtmlHeading6 => Celerity::H6,
|
28
|
+
HtmlUnit::Html::HtmlHiddenInput => Celerity::Hidden,
|
29
|
+
HtmlUnit::Html::HtmlImage => Celerity::Image,
|
30
|
+
HtmlUnit::Html::HtmlLabel => Celerity::Label,
|
31
|
+
HtmlUnit::Html::HtmlListItem => Celerity::Li,
|
32
|
+
HtmlUnit::Html::HtmlMap => Celerity::Map,
|
33
|
+
HtmlUnit::Html::HtmlOption => Celerity::Option,
|
34
|
+
HtmlUnit::Html::HtmlOrderedList => Celerity::Ol,
|
35
|
+
HtmlUnit::Html::HtmlParagraph => Celerity::P,
|
36
|
+
HtmlUnit::Html::HtmlPasswordInput => Celerity::TextField,
|
37
|
+
HtmlUnit::Html::HtmlPreformattedText => Celerity::Pre,
|
38
|
+
HtmlUnit::Html::HtmlRadioButtonInput => Celerity::Radio,
|
39
|
+
HtmlUnit::Html::HtmlSelect => Celerity::SelectList,
|
40
|
+
HtmlUnit::Html::HtmlSpan => Celerity::Span,
|
41
|
+
HtmlUnit::Html::HtmlTable => Celerity::Table,
|
42
|
+
HtmlUnit::Html::HtmlTableBody => Celerity::TableBody,
|
43
|
+
HtmlUnit::Html::HtmlTableCell => Celerity::TableCell,
|
44
|
+
HtmlUnit::Html::HtmlTableFooter => Celerity::TableFooter,
|
45
|
+
HtmlUnit::Html::HtmlTableHeader => Celerity::TableHeader,
|
46
|
+
HtmlUnit::Html::HtmlTableRow => Celerity::TableRow,
|
47
|
+
HtmlUnit::Html::HtmlTextArea => Celerity::TextField,
|
48
|
+
HtmlUnit::Html::HtmlTextInput => Celerity::TextField,
|
49
|
+
HtmlUnit::Html::HtmlUnorderedList => Celerity::Ul
|
50
|
+
}
|
51
|
+
|
52
|
+
def htmlunit2celerity(klass)
|
53
|
+
HtmlUnit2CelerityElement[klass]
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# HtmlUnit will recognize most common file types, but custom ones can be added here.
|
58
|
+
# Used for FileField uploads.
|
59
|
+
#
|
60
|
+
|
61
|
+
ContentTypes = {
|
62
|
+
".bmp" => "image/x-ms-bmp",
|
63
|
+
".doc" => "application/msword",
|
64
|
+
".odg" => "application/vnd.oasis.opendocument.graphics",
|
65
|
+
".odp" => "application/vnd.oasis.opendocument.presentation",
|
66
|
+
".ods" => "application/vnd.oasis.opendocument.spreadsheet",
|
67
|
+
".odt" => "application/vnd.oasis.opendocument.text",
|
68
|
+
".ppt" => "application/vnd.ms-powerpoint",
|
69
|
+
".xls" => "application/vnd.ms-excel",
|
70
|
+
}
|
71
|
+
|
72
|
+
def content_type_for(path)
|
73
|
+
if ct = java.net.URLConnection.getFileNameMap.getContentTypeFor(path)
|
74
|
+
return ct
|
75
|
+
else
|
76
|
+
ContentTypes[File.extname(path).downcase]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def normalize_text(string)
|
81
|
+
string.gsub("\302\240", ' '). # non-breaking space 00A0
|
82
|
+
gsub(/\n|\t/, ''). # get rid of newlines/tabs
|
83
|
+
strip
|
84
|
+
end
|
85
|
+
|
86
|
+
def logger_for(package_string)
|
87
|
+
java.util.logging.Logger.getLogger(package_string)
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Celerity
|
2
|
+
class Browser
|
3
|
+
class << self
|
4
|
+
|
5
|
+
# Added for Watir compatibility - not in use by Celerity
|
6
|
+
attr_accessor :speed, :attach_timeout, :visible
|
7
|
+
# Added for Watir compatibility - not in use by Celerity
|
8
|
+
alias_method :start_window, :start
|
9
|
+
# Added for Watir compatibility - not in use by Celerity
|
10
|
+
def reset_attach_timeout; @attach_timeout = 2.0; end
|
11
|
+
# Added for Watir compatibility - not in use by Celerity
|
12
|
+
def each; end
|
13
|
+
# Added for Watir compatibility - not in use by Celerity
|
14
|
+
def quit; end
|
15
|
+
# Added for Watir compatibility - not in use by Celerity
|
16
|
+
def set_fast_speed; @speed = :fast; end
|
17
|
+
# Added for Watir compatibility - not in use by Celerity
|
18
|
+
def set_slow_speed; @speed = :slow; end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Added for Watir compatibility - not in use by Celerity
|
22
|
+
attr_accessor :visible
|
23
|
+
|
24
|
+
# Added for Watir compatibility - not in use by Celerity
|
25
|
+
def bring_to_front; true; end
|
26
|
+
# Added for Watir compatibility - not in use by Celerity
|
27
|
+
def speed=(s); s end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
module ClickableElement
|
32
|
+
alias_method :click_no_wait, :click
|
33
|
+
end
|
34
|
+
|
35
|
+
module Container
|
36
|
+
alias_method :checkbox, :check_box
|
37
|
+
alias_method :checkBox, :check_box
|
38
|
+
alias_method :body, :tbody
|
39
|
+
alias_method :bodies, :tbodies
|
40
|
+
end
|
41
|
+
|
42
|
+
class Element
|
43
|
+
alias_method :exists, :exists?
|
44
|
+
alias_method :innerText, :text
|
45
|
+
alias_method :inner_text, :text
|
46
|
+
end
|
47
|
+
|
48
|
+
class Image
|
49
|
+
alias_method :hasLoaded?, :loaded?
|
50
|
+
alias_method :has_loaded?, :loaded?
|
51
|
+
alias_method :fileSize, :file_size
|
52
|
+
alias_method :fileCreatedDate, :file_created_date
|
53
|
+
end
|
54
|
+
|
55
|
+
class Link
|
56
|
+
alias_method :click_no_wait, :click
|
57
|
+
end
|
58
|
+
|
59
|
+
class RadioCheckCommon
|
60
|
+
alias_method :is_set?, :set?
|
61
|
+
alias_method :get_state, :set?
|
62
|
+
alias_method :isSet?, :set?
|
63
|
+
alias_method :getState, :set?
|
64
|
+
end
|
65
|
+
|
66
|
+
class SelectList
|
67
|
+
alias_method :getSelectedItems, :selected_options
|
68
|
+
alias_method :getAllContents, :options
|
69
|
+
alias_method :clearSelection, :clear
|
70
|
+
alias_method :clear_selection, :clear
|
71
|
+
alias_method :select_value, :select
|
72
|
+
alias_method :includes?, :include?
|
73
|
+
end
|
74
|
+
|
75
|
+
class TextField
|
76
|
+
alias_method :dragContentsTo, :drag_contents_to
|
77
|
+
alias_method :getContents, :value
|
78
|
+
alias_method :get_contents, :value
|
79
|
+
|
80
|
+
def requires_typing; end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
Celerity::IE = Celerity::Browser
|
data/tasks/jar.rake
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'celerity/version'
|
2
|
+
|
3
|
+
namespace :jar do
|
4
|
+
target_dir = "classes"
|
5
|
+
|
6
|
+
desc "Compile and create celerity-complete-#{Celerity::VERSION::STRING}.jar (includes HtmlUnit)"
|
7
|
+
task :fat do
|
8
|
+
file_name = "pkg/celerity-complete-#{Celerity::VERSION::STRING}.jar"
|
9
|
+
|
10
|
+
ruby_files = Dir['lib/**/*.rb']
|
11
|
+
jar_files = Dir['lib/**/*.jar']
|
12
|
+
resources = Dir['lib/celerity/resources/*']
|
13
|
+
|
14
|
+
rm_rf target_dir if File.exist? target_dir
|
15
|
+
mkdir target_dir
|
16
|
+
mkdir_p resource_dir = "#{target_dir}/celerity/resources"
|
17
|
+
|
18
|
+
sh "jrubyc", "-d", "lib", "-t", target_dir, *ruby_files
|
19
|
+
resources.each { |extra| cp extra, resource_dir }
|
20
|
+
|
21
|
+
jar_files.each do |f|
|
22
|
+
cp f, target_dir
|
23
|
+
end
|
24
|
+
|
25
|
+
top_dir = Dir.pwd
|
26
|
+
chdir target_dir, :verbose => true
|
27
|
+
Dir['*.jar'].each do |file|
|
28
|
+
sh "jar", "xf", file
|
29
|
+
rm_f file
|
30
|
+
end
|
31
|
+
chdir top_dir, :verbose => true
|
32
|
+
|
33
|
+
mkdir_p "pkg"
|
34
|
+
sh "jar", "cvf", file_name, '-C', target_dir, '.'
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "Compile and create celerity-#{Celerity::VERSION::STRING}.jar"
|
38
|
+
task :tiny do
|
39
|
+
file_name = "pkg/celerity-#{Celerity::VERSION::STRING}.jar"
|
40
|
+
|
41
|
+
ruby_files = Dir['lib/**/*.rb']
|
42
|
+
resources = Dir['lib/celerity/resources/*']
|
43
|
+
|
44
|
+
rm_rf target_dir if File.exist? target_dir
|
45
|
+
mkdir target_dir
|
46
|
+
mkdir_p resource_dir = "#{target_dir}/celerity/resources"
|
47
|
+
|
48
|
+
sh "jrubyc", "-d", "lib", "-t", target_dir, *ruby_files
|
49
|
+
resources.each { |extra| cp extra, resource_dir }
|
50
|
+
|
51
|
+
mkdir_p "pkg"
|
52
|
+
sh "jar", "cvf", file_name, '-C', target_dir, '.'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
desc 'Alias for jar:tiny'
|
57
|
+
task :jar => %w[jar:tiny]
|