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.
Files changed (53) hide show
  1. data/CHANGELOG.md +82 -0
  2. data/Gemfile.lock +14 -14
  3. data/bin/quickl +2 -2
  4. data/lib/quickl.rb +162 -2
  5. data/lib/quickl/command.rb +22 -32
  6. data/lib/quickl/command/builder.rb +3 -3
  7. data/lib/quickl/command/delegator.rb +22 -12
  8. data/lib/quickl/command/options.rb +29 -4
  9. data/lib/quickl/command/robustness.rb +5 -12
  10. data/lib/quickl/command/single.rb +4 -6
  11. data/lib/quickl/errors.rb +2 -2
  12. data/lib/quickl/version.rb +2 -2
  13. data/quickl.gemspec +4 -4
  14. data/quickl.noespec +13 -37
  15. data/spec/command/delegator/test_split_argv.rb +41 -0
  16. data/spec/command/{command_building_spec.rb → test_command_building.rb} +4 -4
  17. data/spec/command/{command_name_spec.rb → test_command_name.rb} +1 -6
  18. data/spec/command/{documentation_spec.rb → test_documentation.rb} +1 -1
  19. data/spec/command/{overview_spec.rb → test_overview.rb} +1 -5
  20. data/spec/command/test_parse_options.rb +112 -0
  21. data/spec/command/{requester_spec.rb → test_requester.rb} +1 -1
  22. data/spec/command/test_run.rb +40 -0
  23. data/spec/command/{subcommand_by_name_spec.rb → test_subcommand_by_name.rb} +3 -3
  24. data/spec/command/{subcommands_spec.rb → test_subcommands.rb} +8 -7
  25. data/spec/command/test_usage.rb +11 -0
  26. data/spec/mini_client.rb +36 -6
  27. data/spec/naming/test_command2module.rb +17 -0
  28. data/spec/naming/test_module2command.rb +21 -0
  29. data/spec/quickl/test_command_name.rb +16 -0
  30. data/spec/quickl/test_documentation.rb +32 -0
  31. data/spec/quickl/test_overview.rb +16 -0
  32. data/spec/quickl/test_parse_commandline_args.rb +52 -0
  33. data/spec/quickl/test_split_commandline_args.rb +39 -0
  34. data/spec/quickl/test_sub_command.rb +48 -0
  35. data/spec/quickl/test_super_command.rb +21 -0
  36. data/spec/quickl/test_usage.rb +16 -0
  37. data/spec/{command/robustness/valid_read_file_spec.rb → quickl/test_valid_read_file.rb} +4 -4
  38. data/spec/ruby_tools/fixtures.rb +1 -1
  39. data/spec/ruby_tools/{class_unqualified_name_spec.rb → test_class_unqualified_name.rb} +0 -0
  40. data/spec/ruby_tools/{extract_file_rdoc_spec.rb → test_extract_file_rdoc.rb} +0 -0
  41. data/spec/ruby_tools/{optional_args_block_call_spec.rb → test_optional_args_block.rb} +0 -0
  42. data/spec/ruby_tools/{parent_module_spec.rb → test_parent_module.rb} +0 -0
  43. data/spec/spec_helper.rb +1 -0
  44. data/spec/{quickl_spec.rb → test_quickl.rb} +1 -1
  45. data/tasks/debug_mail.rake +1 -1
  46. data/tasks/spec_test.rake +2 -2
  47. data/tasks/unit_test.rake +2 -2
  48. data/templates/single.erb +1 -1
  49. metadata +96 -76
  50. data/spec/command/run_spec.rb +0 -22
  51. data/spec/command/usage_spec.rb +0 -16
  52. data/spec/naming/command2module_spec.rb +0 -17
  53. 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
- # Parses options
47
- def parse_options(argv)
48
- options.parse!(argv)
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
- unless cmd = referer.subcommand_by_name(name)
10
- raise NoSuchCommand, "No such command #{name}"
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
- if File.file?(file) and File.readable?(file)
19
- file
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 _run(argv = [])
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 *args
22
- b.instance_module Command::Single
19
+ b.document(*args)
20
+ b.instance_module(Command::Single)
23
21
  yield(b) if block_given?
24
22
  end
25
23
  Command
@@ -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
@@ -2,8 +2,8 @@ module Quickl
2
2
  module Version
3
3
 
4
4
  MAJOR = 0
5
- MINOR = 2
6
- TINY = 2
5
+ MINOR = 3
6
+ TINY = 0
7
7
 
8
8
  def self.to_s
9
9
  [ MAJOR, MINOR, TINY ].join('.')
@@ -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.4.0")
129
- s.add_development_dependency("yard", "~> 0.6.4")
130
- s.add_development_dependency("bluecloth", "~> 2.0.9")
131
- s.add_development_dependency("wlang", "~> 0.10.1")
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
@@ -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.3.0
8
-
9
- # Update to match your own configuration.
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.2.2
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
- # Rake is required for developers, as usual
45
- - {name: rake, version: "~> 0.9.2", groups: [development]}
46
- # Bundler is required for developers and is used by the Rakefile
47
- - {name: bundler, version: "~> 1.0", groups: [development]}
48
- # RSpec is required to run 'rake spec'. See tasks/spec.rake
49
- - {name: rspec, version: "~> 2.4.0", groups: [development]}
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 File.expand_path('../../spec_helper', __FILE__)
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 == :hello
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 == MiniClient::Requester
10
+ MiniClient::Factored.super_command.should eq(MiniClient::Requester)
11
11
  MiniClient::Requester.subcommands.should include(MiniClient::Factored)
12
- lambda{ MiniClient::Requester.new.has_command!("factored") }.should_not raise_error
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 File.expand_path('../../spec_helper', __FILE__)
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
@@ -11,7 +11,7 @@ DESCRIPTION
11
11
 
12
12
  EOF
13
13
 
14
- require File.expand_path('../../spec_helper', __FILE__)
14
+ require 'spec_helper'
15
15
  module Quickl
16
16
  describe "Command::documentation /" do
17
17
 
@@ -1,4 +1,4 @@
1
- require File.expand_path('../../spec_helper', __FILE__)
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
@@ -1,4 +1,4 @@
1
- require File.expand_path('../../spec_helper', __FILE__)
1
+ require 'spec_helper'
2
2
  module Quickl
3
3
  describe "Command::requester /" do
4
4
 
@@ -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