quickl 0.1.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/CHANGELOG.md +9 -0
- data/README.md +118 -0
- data/Rakefile +64 -0
- data/bin/quickl +116 -0
- data/examples/delegate/README.md +86 -0
- data/examples/delegate/bin/delegate +9 -0
- data/examples/delegate/lib/delegate.rb +41 -0
- data/examples/delegate/lib/hello_world.rb +39 -0
- data/examples/delegate/lib/help.rb +24 -0
- data/examples/delegate/test/delegate_test.rb +68 -0
- data/examples/hello/README.md +74 -0
- data/examples/hello/hello +57 -0
- data/examples/hello/hello_test.rb +65 -0
- data/examples/helper.rb +6 -0
- data/lib/quickl.rb +47 -0
- data/lib/quickl/command.rb +154 -0
- data/lib/quickl/command/builder.rb +58 -0
- data/lib/quickl/command/delegate.rb +53 -0
- data/lib/quickl/command/options.rb +55 -0
- data/lib/quickl/command/robustness.rb +18 -0
- data/lib/quickl/command/single.rb +27 -0
- data/lib/quickl/errors.rb +196 -0
- data/lib/quickl/ext/object.rb +29 -0
- data/lib/quickl/naming.rb +53 -0
- data/lib/quickl/ruby_tools.rb +60 -0
- data/quickl.gemspec +38 -0
- data/templates/single.erb +40 -0
- data/test/command/command_name.spec +16 -0
- data/test/command/documentation.spec +23 -0
- data/test/command/overview.spec +14 -0
- data/test/command/run.spec +22 -0
- data/test/command/subcommands.spec +20 -0
- data/test/command/usage.spec +16 -0
- data/test/mini_client.rb +59 -0
- data/test/naming/command2module.spec +17 -0
- data/test/naming/module2command.spec +21 -0
- data/test/ruby_tools/class_unqualified_name.spec +28 -0
- data/test/ruby_tools/extract_file_rdoc.spec +28 -0
- data/test/ruby_tools/fixtures.rb +27 -0
- data/test/ruby_tools/fixtures/RubyTools.rdoc +12 -0
- data/test/ruby_tools/fixtures/Utils.rdoc +3 -0
- data/test/ruby_tools/optional_args_block_call.spec +37 -0
- data/test/ruby_tools/parent_module.spec +23 -0
- data/test/spec_helper.rb +13 -0
- data/test/wrapping.rb +39 -0
- metadata +129 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
module Quickl
|
2
|
+
module RubyTools
|
3
|
+
|
4
|
+
# Returns the parent module of a class
|
5
|
+
def parent_module(clazz)
|
6
|
+
name = clazz.name
|
7
|
+
(name =~ /^(.*?)::([^:]+)$/) ? Kernel.eval($1) : nil
|
8
|
+
end
|
9
|
+
module_function :parent_module
|
10
|
+
|
11
|
+
# Returns the unqualified name of a class
|
12
|
+
def class_unqualified_name(clazz)
|
13
|
+
name = clazz.name
|
14
|
+
(name =~ /::([^:]+)$/) ? $1 : name
|
15
|
+
end
|
16
|
+
module_function :class_unqualified_name
|
17
|
+
|
18
|
+
# Makes a call to a block that accepts optional arguments
|
19
|
+
def optional_args_block_call(block, args)
|
20
|
+
if RUBY_VERSION >= "1.9.0"
|
21
|
+
if block.arity == 0
|
22
|
+
block.call
|
23
|
+
else
|
24
|
+
block.call(*args)
|
25
|
+
end
|
26
|
+
else
|
27
|
+
block.call(*args)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
module_function :optional_args_block_call
|
31
|
+
|
32
|
+
# Extracts the rdoc of a given ruby file source.
|
33
|
+
def extract_file_rdoc(file, from = nil, reverse = false)
|
34
|
+
lines = File.readlines(file)
|
35
|
+
if from.nil? and reverse
|
36
|
+
lines = lines.reverse
|
37
|
+
elsif !reverse
|
38
|
+
lines = lines[(from || 0)..-1]
|
39
|
+
else
|
40
|
+
lines = lines[0...(from || -1)].reverse
|
41
|
+
end
|
42
|
+
|
43
|
+
doc, started = [], false
|
44
|
+
lines.each{|line|
|
45
|
+
if /^\s*[#]/ =~ line
|
46
|
+
doc << line
|
47
|
+
started = true
|
48
|
+
elsif started
|
49
|
+
break
|
50
|
+
end
|
51
|
+
}
|
52
|
+
|
53
|
+
doc = reverse ? doc.reverse[0..-1] : doc[0..-1]
|
54
|
+
doc = doc.join("\n")
|
55
|
+
doc.gsub(/^\s*[#] ?/, "")
|
56
|
+
end
|
57
|
+
module_function :extract_file_rdoc
|
58
|
+
|
59
|
+
end # module RubyTools
|
60
|
+
end # module Quickl
|
data/quickl.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path('../lib', __FILE__))
|
2
|
+
require 'rubygems'
|
3
|
+
require 'quickl'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'quickl'
|
7
|
+
s.version = Quickl::VERSION.dup
|
8
|
+
s.date = Time.now.strftime('%Y-%m-%d')
|
9
|
+
|
10
|
+
s.summary = 'Generate Ruby command line apps quickly'
|
11
|
+
s.description = 'Generate Ruby command line apps quickly'
|
12
|
+
|
13
|
+
s.author = 'Bernard Lambeau'
|
14
|
+
s.email = 'blambeau@gmail.com'
|
15
|
+
|
16
|
+
s.require_paths = %w{ lib }
|
17
|
+
|
18
|
+
s.files =
|
19
|
+
Dir['lib/**/*'] +
|
20
|
+
Dir['examples/**/*'] +
|
21
|
+
Dir['templates/**/*'] +
|
22
|
+
Dir['bin/**/*'] +
|
23
|
+
Dir['test/**/*'] +
|
24
|
+
%w{ quickl.gemspec Rakefile README.md CHANGELOG.md }
|
25
|
+
|
26
|
+
s.test_files = s.files.select {|path| path =~ /^test\/.*_test.rb/ }
|
27
|
+
|
28
|
+
s.bindir = "bin"
|
29
|
+
s.executables = ["quickl"]
|
30
|
+
|
31
|
+
s.add_development_dependency('rake')
|
32
|
+
|
33
|
+
s.has_rdoc = true
|
34
|
+
s.rdoc_options = %w< --line-numbers --inline-source --title Quickl --main Quickl >
|
35
|
+
s.extra_rdoc_files = %w< README.md >
|
36
|
+
|
37
|
+
s.homepage = 'http://github.com/blambeau/quickl'
|
38
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
begin
|
2
|
+
require 'quickl'
|
3
|
+
rescue LoadError
|
4
|
+
require 'rubygems'
|
5
|
+
gem 'quickl'
|
6
|
+
retry
|
7
|
+
end
|
8
|
+
|
9
|
+
#
|
10
|
+
# FIX: overview
|
11
|
+
#
|
12
|
+
# SYNOPSIS
|
13
|
+
# #{command_name} [options] ARGS...
|
14
|
+
#
|
15
|
+
# OPTIONS
|
16
|
+
# #{summarized_options}
|
17
|
+
#
|
18
|
+
# DESCRIPTION
|
19
|
+
# FIX: description
|
20
|
+
#
|
21
|
+
class <%= cmd_class_name %> < Quickl::Command(__FILE__, __LINE__)
|
22
|
+
|
23
|
+
VERSION = "0.1.0"
|
24
|
+
|
25
|
+
# Install options
|
26
|
+
options do |opt|
|
27
|
+
<%= option_helpers.collect{|s| tabto(s,4)}.join("\n") %>
|
28
|
+
end
|
29
|
+
|
30
|
+
# Run the command
|
31
|
+
def execute(args)
|
32
|
+
# FIX: do something here
|
33
|
+
puts "Hello #{args.join(' and ')} from #{program_name}"
|
34
|
+
end
|
35
|
+
|
36
|
+
end # class <%= cmd_class_name %>
|
37
|
+
|
38
|
+
if __FILE__ == $0
|
39
|
+
<%= cmd_class_name %>.run(ARGV)
|
40
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
module Quickl
|
3
|
+
describe "Command::command_name /" do
|
4
|
+
|
5
|
+
it "should be installed from inline rdoc" do
|
6
|
+
MiniClient::Say::Hello.command_name.should == "hello"
|
7
|
+
MiniClient::Say::Goodbye.command_name.should == "goodbye"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should be accessible on instance" do
|
11
|
+
MiniClient::Say::Hello.new.command_name.should == "hello"
|
12
|
+
MiniClient::Say::Goodbye.new.command_name.should == "goodbye"
|
13
|
+
end
|
14
|
+
|
15
|
+
end # Command::command_name
|
16
|
+
end # module Quickl
|
@@ -0,0 +1,23 @@
|
|
1
|
+
$hello_doc = <<EOF
|
2
|
+
|
3
|
+
Say hello to the user whose name is requested on the standard input
|
4
|
+
|
5
|
+
SYNOPSIS
|
6
|
+
mini-client say:hello
|
7
|
+
|
8
|
+
DESCRIPTION
|
9
|
+
And an explanation here
|
10
|
+
on multiple lines with replacement: hello
|
11
|
+
|
12
|
+
EOF
|
13
|
+
|
14
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
15
|
+
module Quickl
|
16
|
+
describe "Command::documentation /" do
|
17
|
+
|
18
|
+
it "should be correctly installed" do
|
19
|
+
MiniClient::Say::Hello.documentation.should == $hello_doc[0..-1]
|
20
|
+
end
|
21
|
+
|
22
|
+
end # Command::command
|
23
|
+
end # module Quickl
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
module Quickl
|
3
|
+
describe "Command::overview /" do
|
4
|
+
|
5
|
+
it "should be installed from inline rdoc" do
|
6
|
+
MiniClient::Help.overview.should == "Print help"
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should be installed accessible on instance" do
|
10
|
+
MiniClient::Help.new.overview.should == "Print help"
|
11
|
+
end
|
12
|
+
|
13
|
+
end # Command::overview
|
14
|
+
end # module Quickl
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
module Quickl
|
3
|
+
describe "Command::run /" do
|
4
|
+
|
5
|
+
it "when invoked on a terminal command" do
|
6
|
+
MiniClient::Say::Hello.run.should == :hello
|
7
|
+
MiniClient::Say::Goodbye.run.should == :goodbye
|
8
|
+
end
|
9
|
+
|
10
|
+
it "when invoked on a delegate command" do
|
11
|
+
MiniClient.run(["help"]).should == :help
|
12
|
+
MiniClient::Say.run(["hello"]).should == :hello
|
13
|
+
MiniClient::Say.run(["goodbye"]).should == :goodbye
|
14
|
+
end
|
15
|
+
|
16
|
+
it "when invoked on qualified command names" do
|
17
|
+
MiniClient.run(["say:hello"]).should == :hello
|
18
|
+
MiniClient.run(["say:goodbye"]).should == :goodbye
|
19
|
+
end
|
20
|
+
|
21
|
+
end # Command::command
|
22
|
+
end # module Quickl
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
module Quickl
|
3
|
+
describe "Command::subcommands /" do
|
4
|
+
|
5
|
+
it "should return installed commands in an array" do
|
6
|
+
MiniClient.subcommands.should == [
|
7
|
+
MiniClient::Help,
|
8
|
+
MiniClient::Say
|
9
|
+
]
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should return installed commands in an array" do
|
13
|
+
MiniClient::Say.subcommands.should == [
|
14
|
+
MiniClient::Say::Hello,
|
15
|
+
MiniClient::Say::Goodbye
|
16
|
+
]
|
17
|
+
end
|
18
|
+
|
19
|
+
end # Command::subcommand
|
20
|
+
end # module Quickl
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
module Quickl
|
3
|
+
describe "Command::usage /" do
|
4
|
+
|
5
|
+
it "should be installed from inline rdoc" do
|
6
|
+
MiniClient::Say::Hello.usage.should == "mini-client say:hello"
|
7
|
+
MiniClient::Say::Goodbye.usage.should == "mini-client say:goodbye"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should be accessible on instance" do
|
11
|
+
MiniClient::Say::Hello.new.usage.should == "mini-client say:hello"
|
12
|
+
MiniClient::Say::Goodbye.new.usage.should == "mini-client say:goodbye"
|
13
|
+
end
|
14
|
+
|
15
|
+
end # Command::usage
|
16
|
+
end # module Quickl
|
data/test/mini_client.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
#
|
2
|
+
# MiniClient main command
|
3
|
+
#
|
4
|
+
class MiniClient < Quickl::Delegate(__FILE__, __LINE__)
|
5
|
+
|
6
|
+
#
|
7
|
+
# Print help
|
8
|
+
#
|
9
|
+
# SYNOPSIS
|
10
|
+
# #{MiniClient.command_name} help
|
11
|
+
#
|
12
|
+
# DESCRIPTION
|
13
|
+
# #{command_name} prints help
|
14
|
+
#
|
15
|
+
class Help < Quickl::Command(__FILE__, __LINE__)
|
16
|
+
|
17
|
+
def run(*args)
|
18
|
+
:help
|
19
|
+
end
|
20
|
+
|
21
|
+
end # class Help
|
22
|
+
|
23
|
+
class Say < Quickl::Delegate(__FILE__, __LINE__)
|
24
|
+
|
25
|
+
#
|
26
|
+
# Say hello to the user whose name is requested on the standard input
|
27
|
+
#
|
28
|
+
# SYNOPSIS
|
29
|
+
# #{MiniClient.command_name} say:hello
|
30
|
+
#
|
31
|
+
# DESCRIPTION
|
32
|
+
# And an explanation here
|
33
|
+
# on multiple lines with replacement: #{command_name}
|
34
|
+
#
|
35
|
+
class Hello < Quickl::Command(__FILE__, __LINE__)
|
36
|
+
|
37
|
+
def run(*args)
|
38
|
+
:hello
|
39
|
+
end
|
40
|
+
|
41
|
+
end # class Hello
|
42
|
+
|
43
|
+
#
|
44
|
+
# Say goodbye to the currently connected user
|
45
|
+
#
|
46
|
+
# SYNOPSIS
|
47
|
+
# #{MiniClient.command_name} say:goodbye
|
48
|
+
#
|
49
|
+
class Goodbye < Quickl::Command(__FILE__, __LINE__)
|
50
|
+
|
51
|
+
def run(*args)
|
52
|
+
:goodbye
|
53
|
+
end
|
54
|
+
|
55
|
+
end # class Goodbye
|
56
|
+
|
57
|
+
end # class Say
|
58
|
+
|
59
|
+
end # module MiniClient
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
module Quickl
|
3
|
+
describe "Naming::command2module /" do
|
4
|
+
include Naming
|
5
|
+
|
6
|
+
it "should capitalize first char" do
|
7
|
+
command2module("say").should == "Say"
|
8
|
+
command2module(:say).should == :Say
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should capitalize support dashes" do
|
12
|
+
command2module("say-hello").should == "SayHello"
|
13
|
+
command2module(:"say-hello").should == :SayHello
|
14
|
+
end
|
15
|
+
|
16
|
+
end # module Quickl
|
17
|
+
end # module Quickl
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
module Quickl
|
3
|
+
describe "Naming::module2command /" do
|
4
|
+
include Naming
|
5
|
+
|
6
|
+
it "should uncapitalize first char" do
|
7
|
+
module2command("Say").should == "say"
|
8
|
+
module2command(:Say).should == :say
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should uncapitalize and introduce dashes" do
|
12
|
+
module2command("SayHello").should == "say-hello"
|
13
|
+
module2command(:"SayHello").should == :"say-hello"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should support taking modules as argument" do
|
17
|
+
module2command(Quickl::Command).should == "command"
|
18
|
+
end
|
19
|
+
|
20
|
+
end # module Quickl
|
21
|
+
end # module Quickl
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.expand_path('../fixtures', __FILE__)
|
2
|
+
module Quickl
|
3
|
+
describe "RubyTools#class_unqualified_name /" do
|
4
|
+
|
5
|
+
subject{ RubyTools::class_unqualified_name(clazz) }
|
6
|
+
|
7
|
+
describe "when called on unqualified class" do
|
8
|
+
let(:clazz){ ::String }
|
9
|
+
it{ should == "String" }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "when called on qualified class" do
|
13
|
+
let(:clazz){ RubyTools }
|
14
|
+
it{ should == "RubyTools" }
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "when called on long qualified class" do
|
18
|
+
let(:clazz){ Quickl::Fixtures::Utils }
|
19
|
+
it{ should == "Utils" }
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "when piped with parent_module" do
|
23
|
+
let(:clazz){ RubyTools::parent_module(Quickl::Fixtures::Utils) }
|
24
|
+
it{ should == "Fixtures" }
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.expand_path('../fixtures', __FILE__)
|
2
|
+
module Quickl
|
3
|
+
describe "RubyTools#extract_file_rdoc /" do
|
4
|
+
|
5
|
+
let(:file){ File.expand_path('../fixtures.rb', __FILE__) }
|
6
|
+
|
7
|
+
describe "when used without line and reverse options" do
|
8
|
+
|
9
|
+
subject{ RubyTools::extract_file_rdoc(file) }
|
10
|
+
|
11
|
+
it "should be as expected" do
|
12
|
+
subject.should == File.read(File.expand_path('../fixtures/RubyTools.rdoc', __FILE__))
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "when used with line and reverse options" do
|
18
|
+
|
19
|
+
subject{ RubyTools::extract_file_rdoc(file, 23, true) }
|
20
|
+
|
21
|
+
it "should be as expected" do
|
22
|
+
subject.should == File.read(File.expand_path('../fixtures/Utils.rdoc', __FILE__))
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end # RubyTools#extract_file_rdoc
|
28
|
+
end # module Quickl
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
module Quickl
|
3
|
+
module Fixtures
|
4
|
+
|
5
|
+
#
|
6
|
+
# This is a fixtures helper that matches documentation conventions.
|
7
|
+
#
|
8
|
+
# This is a second paragraph
|
9
|
+
# That append on two lines
|
10
|
+
#
|
11
|
+
#
|
12
|
+
# WARNING:
|
13
|
+
# This kind of indentation should not be interpreted as code
|
14
|
+
#
|
15
|
+
# But this one yes
|
16
|
+
#
|
17
|
+
module RubyTools
|
18
|
+
end # module RubyTools
|
19
|
+
|
20
|
+
#
|
21
|
+
# This is the documentation of the Utils module
|
22
|
+
#
|
23
|
+
module Utils
|
24
|
+
end # module Utils
|
25
|
+
|
26
|
+
end # module Fixtures
|
27
|
+
end # module Quickl
|