quickl 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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