quickl 0.2.2 → 0.3.0
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 +82 -0
- data/Gemfile.lock +14 -14
- data/bin/quickl +2 -2
- data/lib/quickl.rb +162 -2
- data/lib/quickl/command.rb +22 -32
- data/lib/quickl/command/builder.rb +3 -3
- data/lib/quickl/command/delegator.rb +22 -12
- data/lib/quickl/command/options.rb +29 -4
- data/lib/quickl/command/robustness.rb +5 -12
- data/lib/quickl/command/single.rb +4 -6
- data/lib/quickl/errors.rb +2 -2
- data/lib/quickl/version.rb +2 -2
- data/quickl.gemspec +4 -4
- data/quickl.noespec +13 -37
- data/spec/command/delegator/test_split_argv.rb +41 -0
- data/spec/command/{command_building_spec.rb → test_command_building.rb} +4 -4
- data/spec/command/{command_name_spec.rb → test_command_name.rb} +1 -6
- data/spec/command/{documentation_spec.rb → test_documentation.rb} +1 -1
- data/spec/command/{overview_spec.rb → test_overview.rb} +1 -5
- data/spec/command/test_parse_options.rb +112 -0
- data/spec/command/{requester_spec.rb → test_requester.rb} +1 -1
- data/spec/command/test_run.rb +40 -0
- data/spec/command/{subcommand_by_name_spec.rb → test_subcommand_by_name.rb} +3 -3
- data/spec/command/{subcommands_spec.rb → test_subcommands.rb} +8 -7
- data/spec/command/test_usage.rb +11 -0
- data/spec/mini_client.rb +36 -6
- data/spec/naming/test_command2module.rb +17 -0
- data/spec/naming/test_module2command.rb +21 -0
- data/spec/quickl/test_command_name.rb +16 -0
- data/spec/quickl/test_documentation.rb +32 -0
- data/spec/quickl/test_overview.rb +16 -0
- data/spec/quickl/test_parse_commandline_args.rb +52 -0
- data/spec/quickl/test_split_commandline_args.rb +39 -0
- data/spec/quickl/test_sub_command.rb +48 -0
- data/spec/quickl/test_super_command.rb +21 -0
- data/spec/quickl/test_usage.rb +16 -0
- data/spec/{command/robustness/valid_read_file_spec.rb → quickl/test_valid_read_file.rb} +4 -4
- data/spec/ruby_tools/fixtures.rb +1 -1
- data/spec/ruby_tools/{class_unqualified_name_spec.rb → test_class_unqualified_name.rb} +0 -0
- data/spec/ruby_tools/{extract_file_rdoc_spec.rb → test_extract_file_rdoc.rb} +0 -0
- data/spec/ruby_tools/{optional_args_block_call_spec.rb → test_optional_args_block.rb} +0 -0
- data/spec/ruby_tools/{parent_module_spec.rb → test_parent_module.rb} +0 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/{quickl_spec.rb → test_quickl.rb} +1 -1
- data/tasks/debug_mail.rake +1 -1
- data/tasks/spec_test.rake +2 -2
- data/tasks/unit_test.rake +2 -2
- data/templates/single.erb +1 -1
- metadata +96 -76
- data/spec/command/run_spec.rb +0 -22
- data/spec/command/usage_spec.rb +0 -16
- data/spec/naming/command2module_spec.rb +0 -17
- data/spec/naming/module2command_spec.rb +0 -21
@@ -43,13 +43,38 @@ module Quickl
|
|
43
43
|
@options ||= self.class.build_options(self)
|
44
44
|
end
|
45
45
|
|
46
|
-
#
|
47
|
-
|
48
|
-
|
46
|
+
#
|
47
|
+
# Parses options in `argv` with an OptionParser instance and returns
|
48
|
+
# non-options arguments.
|
49
|
+
#
|
50
|
+
# The following example illustrates the role of `sep_support`
|
51
|
+
#
|
52
|
+
# parse_options %w{--verbose hello -- quickl --say and world}
|
53
|
+
# # => ["hello", "quickl", "--say", "and", "world"]
|
54
|
+
#
|
55
|
+
# parse_options %w{--verbose hello -- quickl --say and world}, :keep
|
56
|
+
# # => ["hello", "--", "quickl", "--say", "and", "world"]
|
57
|
+
#
|
58
|
+
# parse_options %w{--verbose hello -- quickl --say and world}, :split
|
59
|
+
# # => [["hello"], ["quickl", "--say", and", "world"]]
|
60
|
+
#
|
61
|
+
def parse_options(argv, sep_support = :none)
|
62
|
+
case sep_support
|
63
|
+
when NilClass, :none
|
64
|
+
options.parse!(argv)
|
65
|
+
when :split, :keep
|
66
|
+
parts = Quickl.split_commandline_args(argv)
|
67
|
+
parts[0] = options.parse!(parts[0])
|
68
|
+
if sep_support == :keep
|
69
|
+
parts.inject(nil){|memo,arr| memo ? memo + ["--"] + arr : arr.dup}
|
70
|
+
else
|
71
|
+
parts
|
72
|
+
end
|
73
|
+
end
|
49
74
|
rescue OptionParser::ParseError => ex
|
50
75
|
raise Quickl::InvalidOption, ex.message, ex.backtrace
|
51
76
|
end
|
52
77
|
|
53
78
|
end # module InstanceMethods
|
54
79
|
end # module Command::Options
|
55
|
-
end # module Quickl
|
80
|
+
end # module Quickl
|
@@ -6,24 +6,17 @@ module Quickl
|
|
6
6
|
# Checks that a command whose name is given exists
|
7
7
|
# or raises a NoSuchCommand.
|
8
8
|
def has_command!(name, referer = self.class)
|
9
|
-
|
10
|
-
|
11
|
-
end
|
12
|
-
cmd
|
9
|
+
Quickl.deprecated("Command#has_command!", "Quickl.sub_command!", caller)
|
10
|
+
Quickl.sub_command!(referer, name)
|
13
11
|
end
|
14
12
|
|
15
13
|
# Checks that _file_ is a readable file or raises an error.
|
16
14
|
# Returns _file_ on success.
|
17
15
|
def valid_read_file!(file, error_class = nil, msg = nil)
|
18
|
-
|
19
|
-
|
20
|
-
else
|
21
|
-
error_class ||= Quickl::IOAccessError
|
22
|
-
msg ||= "Not a file or not readable: #{file}"
|
23
|
-
raise error_class, msg, caller
|
24
|
-
end
|
16
|
+
Quickl.deprecated("Command#valid_read_file!", "Quickl.valid_read_file!", caller)
|
17
|
+
Quickl.valid_read_file!(file, error_class, msg)
|
25
18
|
end
|
26
19
|
|
27
20
|
end # module Robustness
|
28
21
|
end # class Command
|
29
|
-
end # module Quickl
|
22
|
+
end # module Quickl
|
@@ -3,11 +3,9 @@ module Quickl
|
|
3
3
|
# Instance method for being a single command
|
4
4
|
module Command::Single
|
5
5
|
|
6
|
-
# Command arguments after options parsing
|
7
|
-
attr_reader :args
|
8
|
-
|
9
6
|
# Run the command by delegation
|
10
|
-
def
|
7
|
+
def run(argv = [], requester = nil)
|
8
|
+
@requester = requester
|
11
9
|
execute(parse_options(argv))
|
12
10
|
end
|
13
11
|
|
@@ -18,8 +16,8 @@ module Quickl
|
|
18
16
|
#
|
19
17
|
def self.Command(*args)
|
20
18
|
command_builder do |b|
|
21
|
-
b.document
|
22
|
-
b.instance_module
|
19
|
+
b.document(*args)
|
20
|
+
b.instance_module(Command::Single)
|
23
21
|
yield(b) if block_given?
|
24
22
|
end
|
25
23
|
Command
|
data/lib/quickl/errors.rb
CHANGED
@@ -107,9 +107,9 @@ module Quickl
|
|
107
107
|
|
108
108
|
def react!
|
109
109
|
msg = if (self.message || "").empty?
|
110
|
-
command.help
|
110
|
+
command.class.help
|
111
111
|
else
|
112
|
-
self.message.to_s + "\n" + command.help
|
112
|
+
self.message.to_s + "\n" + command.class.help
|
113
113
|
end
|
114
114
|
raise Exit.new(self.exit_code), msg, backtrace
|
115
115
|
end
|
data/lib/quickl/version.rb
CHANGED
data/quickl.gemspec
CHANGED
@@ -125,10 +125,10 @@ Gem::Specification.new do |s|
|
|
125
125
|
#
|
126
126
|
s.add_development_dependency("rake", "~> 0.9.2")
|
127
127
|
s.add_development_dependency("bundler", "~> 1.0")
|
128
|
-
s.add_development_dependency("rspec", "~> 2.
|
129
|
-
s.add_development_dependency("yard", "~> 0.
|
130
|
-
s.add_development_dependency("bluecloth", "~> 2.0
|
131
|
-
s.add_development_dependency("wlang", "~> 0.10.
|
128
|
+
s.add_development_dependency("rspec", "~> 2.6.0")
|
129
|
+
s.add_development_dependency("yard", "~> 0.7.2")
|
130
|
+
s.add_development_dependency("bluecloth", "~> 2.1.0")
|
131
|
+
s.add_development_dependency("wlang", "~> 0.10.2")
|
132
132
|
|
133
133
|
|
134
134
|
# The version of ruby required by this gem
|
data/quickl.noespec
CHANGED
@@ -1,58 +1,34 @@
|
|
1
1
|
# Noe template for ruby gem libraries (https://github.com/blambeau/noe) - short version
|
2
2
|
# Run 'noe show-spec' and 'noe help show-spec' for additional details.
|
3
|
-
|
4
|
-
# Don't remove this entry!
|
5
3
|
template-info:
|
6
4
|
name: "ruby"
|
7
|
-
version: 1.
|
8
|
-
|
9
|
-
|
5
|
+
version: 1.4.0
|
6
|
+
manifest:
|
7
|
+
tasks/unit_test.rake:
|
8
|
+
safe-override: false
|
9
|
+
tasks/spec_test.rake:
|
10
|
+
safe-override: false
|
10
11
|
variables:
|
11
|
-
# A ruby lower case project name.
|
12
12
|
lower:
|
13
13
|
quickl
|
14
|
-
|
15
|
-
# A ruby upper case project name.
|
16
14
|
upper:
|
17
15
|
Quickl
|
18
|
-
|
19
|
-
# Version of your library
|
20
16
|
version:
|
21
|
-
0.
|
22
|
-
|
23
|
-
# Project summary (~ 1 line).
|
17
|
+
0.3.0
|
24
18
|
summary: |-
|
25
19
|
Helper to create commandline ruby programs
|
26
|
-
|
27
|
-
# Project description (~ 5 lines). Project description should be more complete
|
28
|
-
# than the summary and will be used to describe your gem on rubygems.org
|
29
20
|
description: |-
|
30
21
|
Quickl helps you creating commandline ruby programs. From simple commands
|
31
22
|
with options to complex delegators with subcommands, global and local
|
32
23
|
options.
|
33
|
-
|
34
|
-
# Authors of the project (- {name: Bob, email: bob@gmail.com}, ...)
|
35
24
|
authors:
|
36
25
|
- { name: "Bernard Lambeau", email: blambeau@gmail.com }
|
37
|
-
|
38
|
-
# Web links for the project (- http://..., - http://...).
|
39
26
|
links:
|
40
27
|
- http://github.com/blambeau/quickl
|
41
|
-
|
42
|
-
# Gem dependencies. (- {name: ..., version: ..., groups: [...]}, ...)
|
43
28
|
dependencies:
|
44
|
-
|
45
|
-
- {name:
|
46
|
-
|
47
|
-
- {name:
|
48
|
-
|
49
|
-
- {name:
|
50
|
-
# YARD and BlueCloth are required to run 'rake yard'. See tasks/yard.rake
|
51
|
-
- {name: yard, version: "~> 0.6.4", groups: [development]}
|
52
|
-
- {name: bluecloth, version: "~> 2.0.9", groups: [development]}
|
53
|
-
# wlang is required to run 'rake debug_mail'. See tasks/debug_mail.rake
|
54
|
-
- {name: wlang, version: "~> 0.10.1", groups: [development]}
|
55
|
-
|
56
|
-
rake_tasks:
|
57
|
-
unit_test:
|
58
|
-
pattern: examples/**/*_test.rb
|
29
|
+
- {name: rake, version: "~> 0.9.2", groups: [development]}
|
30
|
+
- {name: bundler, version: "~> 1.0", groups: [development]}
|
31
|
+
- {name: rspec, version: "~> 2.6.0", groups: [development]}
|
32
|
+
- {name: yard, version: "~> 0.7.2", groups: [development]}
|
33
|
+
- {name: bluecloth, version: "~> 2.1.0", groups: [development]}
|
34
|
+
- {name: wlang, version: "~> 0.10.2", groups: [development]}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Quickl
|
3
|
+
module Command::Delegator
|
4
|
+
describe "InstanceMethods#split_argv" do
|
5
|
+
|
6
|
+
let(:cmd){ Object.new.extend(InstanceMethods) }
|
7
|
+
subject{ cmd.send(:split_argv, argv) }
|
8
|
+
|
9
|
+
describe "on an empty array" do
|
10
|
+
let(:argv){ [] }
|
11
|
+
it { should eql([[],[]]) }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "on an array without options" do
|
15
|
+
let(:argv){ ["hello", "world"] }
|
16
|
+
it { should eql([[],["hello", "world"]]) }
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "on an array with one single double dashed options" do
|
20
|
+
let(:argv){ ["--verbose", "hello", "--world"] }
|
21
|
+
it { should eql([["--verbose"],["hello", "--world"]]) }
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "on an array with one single dashed options" do
|
25
|
+
let(:argv){ ["-Ilib", "hello", "--world"] }
|
26
|
+
it { should eql([["-Ilib"],["hello", "--world"]]) }
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "on an array with multiple options" do
|
30
|
+
let(:argv){ ["--verbose", "-Ilib", "hello", "--world"] }
|
31
|
+
it { should eql([["--verbose","-Ilib"],["hello", "--world"]]) }
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "in presence of an argument separator" do
|
35
|
+
let(:argv){ ["--verbose", "-Ilib", "--", "-b", "hello", "--world"] }
|
36
|
+
it { should eql([["--verbose","-Ilib"],["--", "-b", "hello", "--world"]]) }
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
module Quickl
|
3
3
|
describe "Command building /" do
|
4
4
|
|
5
5
|
it "should execute callback methods" do
|
6
|
-
MiniClient::Factored.run.should
|
6
|
+
MiniClient::Factored.run.should eq(:hello)
|
7
7
|
end
|
8
8
|
|
9
9
|
it "should install hierarchy correctly when command_parent= is used" do
|
10
|
-
MiniClient::Factored.super_command.should
|
10
|
+
MiniClient::Factored.super_command.should eq(MiniClient::Requester)
|
11
11
|
MiniClient::Requester.subcommands.should include(MiniClient::Factored)
|
12
|
-
lambda{ MiniClient::Requester
|
12
|
+
lambda{ Quickl.sub_command!(MiniClient::Requester, "factored") }.should_not raise_error
|
13
13
|
end
|
14
14
|
|
15
15
|
end # Command::command_name
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
module Quickl
|
3
3
|
describe "Command::command_name /" do
|
4
4
|
|
@@ -7,10 +7,5 @@ module Quickl
|
|
7
7
|
MiniClient::Say::Goodbye.command_name.should == "goodbye"
|
8
8
|
end
|
9
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
10
|
end # Command::command_name
|
16
11
|
end # module Quickl
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
module Quickl
|
3
3
|
describe "Command::overview /" do
|
4
4
|
|
@@ -6,9 +6,5 @@ module Quickl
|
|
6
6
|
MiniClient::Help.overview.should == "Print help"
|
7
7
|
end
|
8
8
|
|
9
|
-
it "should be installed accessible on instance" do
|
10
|
-
MiniClient::Help.new.overview.should == "Print help"
|
11
|
-
end
|
12
|
-
|
13
9
|
end # Command::overview
|
14
10
|
end # module Quickl
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe "Command#parse_options" do
|
3
|
+
|
4
|
+
let(:cmd){ MiniClient::Say::Args.new }
|
5
|
+
subject{ cmd.parse_options(argv, sep_support) }
|
6
|
+
|
7
|
+
describe "when no separator support" do
|
8
|
+
let(:sep_support){ :none }
|
9
|
+
|
10
|
+
describe "on empty array" do
|
11
|
+
let(:argv){ [] }
|
12
|
+
it { should eq([]) }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "without any option nor separator" do
|
16
|
+
let(:argv){ ["hello", "world"] }
|
17
|
+
it { should eq(argv) }
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "with disseminated options" do
|
21
|
+
let(:argv){ %w{-i hello --joption -k world} }
|
22
|
+
it { should eq(%w{hello world}) }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "with an option separator" do
|
26
|
+
let(:argv){ %w{-i hello -- --joption -k world} }
|
27
|
+
it { should eq(%w{hello --joption -k world}) }
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "when separator support set to :keep" do
|
33
|
+
let(:sep_support){ :keep }
|
34
|
+
|
35
|
+
describe "on empty array" do
|
36
|
+
let(:argv){ [] }
|
37
|
+
it { should eq([]) }
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "without any option nor separator" do
|
41
|
+
let(:argv){ ["hello", "world"] }
|
42
|
+
it { should eq(argv) }
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "with disseminated options" do
|
46
|
+
let(:argv){ %w{-i hello --joption -k world} }
|
47
|
+
it { should eq(%w{hello world}) }
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "with an option separator" do
|
51
|
+
let(:argv){ %w{-i hello -- --joption -k world} }
|
52
|
+
it { should eq(%w{hello -- --joption -k world}) }
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "with an option separator at first" do
|
56
|
+
let(:argv){ %w{-- -i hello -- --joption -k world} }
|
57
|
+
it { should eq(%w{-- -i hello -- --joption -k world}) }
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "with an option separator at last" do
|
61
|
+
let(:argv){ %w{-i hello --joption -k world --} }
|
62
|
+
it { should eq(%w{hello world --}) }
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "with multiple option separators" do
|
66
|
+
let(:argv){ %w{-i hello -- --joption -k -- world --} }
|
67
|
+
it { should eq(%w{hello -- --joption -k -- world --}) }
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "when separator support set to :split" do
|
73
|
+
let(:sep_support){ :split }
|
74
|
+
|
75
|
+
describe "on empty array" do
|
76
|
+
let(:argv){ [] }
|
77
|
+
it { should eq([[]]) }
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "without any option nor separator" do
|
81
|
+
let(:argv){ ["hello", "world"] }
|
82
|
+
it { should eq([argv]) }
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "with disseminated options" do
|
86
|
+
let(:argv){ %w{-i hello --joption -k world} }
|
87
|
+
it { should eq([%w{hello world}]) }
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "with an option separator" do
|
91
|
+
let(:argv){ %w{-i hello -- --joption -k world} }
|
92
|
+
it { should eq([%w{hello},%w{--joption -k world}]) }
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "with an option separator at first" do
|
96
|
+
let(:argv){ %w{-- -i hello -- --joption -k world} }
|
97
|
+
it { should eq([%w{}, %w{-i hello}, %w{--joption -k world}]) }
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "with an option separator at last" do
|
101
|
+
let(:argv){ %w{-i hello --joption -k world --} }
|
102
|
+
it { should eq([%w{hello world},%w{}]) }
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "with multiple option separators" do
|
106
|
+
let(:argv){ %w{-i hello -- --joption -k -- world --} }
|
107
|
+
it { should eq([%w{hello}, %w{--joption -k}, %w{world}, %w{}]) }
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
module Quickl
|
3
|
+
describe "Command::run /" do
|
4
|
+
|
5
|
+
specify "when invoked on a terminal command" do
|
6
|
+
MiniClient::Say::Hello.run.should eql(:hello)
|
7
|
+
MiniClient::Say::Goodbye.run.should eql(:goodbye)
|
8
|
+
end
|
9
|
+
|
10
|
+
specify "when invoked on a delegator command" do
|
11
|
+
MiniClient.run(["help"]).should eql(:help)
|
12
|
+
MiniClient::Say.run(["hello"]).should eql(:hello)
|
13
|
+
MiniClient::Say.run(["goodbye"]).should eql(:goodbye)
|
14
|
+
end
|
15
|
+
|
16
|
+
specify "when invoked on qualified command names" do
|
17
|
+
MiniClient.run(["say:hello"]).should eql(:hello)
|
18
|
+
MiniClient.run(["say:goodbye"]).should eql(:goodbye)
|
19
|
+
end
|
20
|
+
|
21
|
+
specify "when --options are passed to a delegator command" do
|
22
|
+
mini = MiniClient.new
|
23
|
+
mini.run(%w{--verbose say:hello}).should eql(:hello)
|
24
|
+
mini.verbose.should be_true
|
25
|
+
end
|
26
|
+
|
27
|
+
specify "when -option is passed to a delegator command" do
|
28
|
+
mini = MiniClient.new
|
29
|
+
mini.run(%w{-v say:hello}).should eql(:hello)
|
30
|
+
mini.verbose.should be_true
|
31
|
+
end
|
32
|
+
|
33
|
+
specify "when --no-option is passed to a delegator command" do
|
34
|
+
mini = MiniClient.new
|
35
|
+
mini.run(%w{--no-verbose say:hello}).should eql(:hello)
|
36
|
+
mini.verbose.should be_false
|
37
|
+
end
|
38
|
+
|
39
|
+
end # Command::command
|
40
|
+
end # module Quickl
|