quickl 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/CHANGELOG.md +9 -0
  2. data/README.md +118 -0
  3. data/Rakefile +64 -0
  4. data/bin/quickl +116 -0
  5. data/examples/delegate/README.md +86 -0
  6. data/examples/delegate/bin/delegate +9 -0
  7. data/examples/delegate/lib/delegate.rb +41 -0
  8. data/examples/delegate/lib/hello_world.rb +39 -0
  9. data/examples/delegate/lib/help.rb +24 -0
  10. data/examples/delegate/test/delegate_test.rb +68 -0
  11. data/examples/hello/README.md +74 -0
  12. data/examples/hello/hello +57 -0
  13. data/examples/hello/hello_test.rb +65 -0
  14. data/examples/helper.rb +6 -0
  15. data/lib/quickl.rb +47 -0
  16. data/lib/quickl/command.rb +154 -0
  17. data/lib/quickl/command/builder.rb +58 -0
  18. data/lib/quickl/command/delegate.rb +53 -0
  19. data/lib/quickl/command/options.rb +55 -0
  20. data/lib/quickl/command/robustness.rb +18 -0
  21. data/lib/quickl/command/single.rb +27 -0
  22. data/lib/quickl/errors.rb +196 -0
  23. data/lib/quickl/ext/object.rb +29 -0
  24. data/lib/quickl/naming.rb +53 -0
  25. data/lib/quickl/ruby_tools.rb +60 -0
  26. data/quickl.gemspec +38 -0
  27. data/templates/single.erb +40 -0
  28. data/test/command/command_name.spec +16 -0
  29. data/test/command/documentation.spec +23 -0
  30. data/test/command/overview.spec +14 -0
  31. data/test/command/run.spec +22 -0
  32. data/test/command/subcommands.spec +20 -0
  33. data/test/command/usage.spec +16 -0
  34. data/test/mini_client.rb +59 -0
  35. data/test/naming/command2module.spec +17 -0
  36. data/test/naming/module2command.spec +21 -0
  37. data/test/ruby_tools/class_unqualified_name.spec +28 -0
  38. data/test/ruby_tools/extract_file_rdoc.spec +28 -0
  39. data/test/ruby_tools/fixtures.rb +27 -0
  40. data/test/ruby_tools/fixtures/RubyTools.rdoc +12 -0
  41. data/test/ruby_tools/fixtures/Utils.rdoc +3 -0
  42. data/test/ruby_tools/optional_args_block_call.spec +37 -0
  43. data/test/ruby_tools/parent_module.spec +23 -0
  44. data/test/spec_helper.rb +13 -0
  45. data/test/wrapping.rb +39 -0
  46. metadata +129 -0
@@ -0,0 +1,9 @@
1
+ # 0.1.1 / 2010-12-24
2
+
3
+ * Fixed gemspec and binaries problems
4
+ * First official release
5
+
6
+ # 0.1.0 / 2010-12-22
7
+
8
+ * Birthday!
9
+
@@ -0,0 +1,118 @@
1
+ # Quickl
2
+
3
+ * http://github.com/blambeau/quickl
4
+
5
+ ## Description
6
+
7
+ Quickl helps you create commandline programs as simply as:
8
+
9
+ #
10
+ # Short description here
11
+ #
12
+ # SYNOPSIS
13
+ # Usage: ...
14
+ #
15
+ # OPTIONS:
16
+ # #{sumarized_options}
17
+ #
18
+ # DESCRIPTION
19
+ # Long description here...
20
+ #
21
+ class SimpleCommand < Quickl::Command(__FILE__, __LINE__)
22
+
23
+ # install options below
24
+ options do |opt|
25
+ # _opt_ is an OptionParser instance
26
+ end
27
+
28
+ # install the code to run the command
29
+ def execute(args)
30
+ # _args_ are non-option command line parameters
31
+ end
32
+
33
+ end
34
+
35
+ Running them as simply as:
36
+
37
+ SimpleCommand.run(ARGV)
38
+
39
+ From simple command to complex delegate (_ala_ 'git [--version] [--help] COMMAND [cmd options] ARGS...'), Quickl provides (or aims at providing) the following features:
40
+
41
+ * Simple command creations via simple classes
42
+ * Delegate commands and categories via ruby namespaces and naming conventions
43
+ * Command help and documentation provided through _rdoc_
44
+ * Command options via standard OptionParser
45
+ * Error handling trought special blocks, assertions methods and dedicated Error classes
46
+ * Unit/spec testing of commands, as they are part of the software
47
+
48
+ ## Install
49
+
50
+ sudo gem install quickl
51
+
52
+ ## Then?
53
+
54
+ Try this:
55
+
56
+ # have a look at options
57
+ quickl --help
58
+
59
+ # generate a hello.rb single command
60
+ quickl --layout=single --options=help,version hello > hello.rb
61
+
62
+ # test your command
63
+ ruby hello.rb --help
64
+ ruby hello.rb --version
65
+ ruby hello.rb bob
66
+
67
+ # see what has been generated
68
+ cat hello.rb
69
+
70
+ Additional examples (see examples folder):
71
+
72
+ * [hello world example](https://github.com/blambeau/quickl/blob/master/examples/hello_world)
73
+ * [delegate example](https://github.com/blambeau/quickl/blob/master/examples/delegate)
74
+
75
+ ## Version policy
76
+
77
+ Until version 1.0.0, moditications of public interfaces increase the minor version, while other changes increase the tiny version. After version 1.0.0, same changes will affect major and minor versions, respectively.
78
+
79
+ 0.1.0 -> 0.1.1 # enhancements and private API changes
80
+ 0.1.0 -> 0.2.0 # broken API on public interfaces
81
+
82
+ Public interfaces are:
83
+
84
+ * Quickl::Command and Quickl::Delegate calls
85
+ * DSL methods used in "subclasses" built by Quickl::Command and Quickl::Delegate
86
+ * RDoc -> command line documentation recognizers (synopsis, overview, documentation, ...)
87
+ * Naming conventions (module <-> command conversions)
88
+ * Default reactions to errors (Quickl::Help, Quickl::Exit, ...)
89
+
90
+ Until version 1.0.0, to preserve your application from hurting changes you should require quickl as follows:
91
+
92
+ gem 'quickl', '< 0.2.0' # Assuming current version is 0.1.xx
93
+ require 'quickl'
94
+
95
+ ## Licence
96
+
97
+ (The MIT License)
98
+
99
+ Copyright (c) 2010 Bernard Lambeau <blambeau@gmail.com>
100
+
101
+ Permission is hereby granted, free of charge, to any person obtaining
102
+ a copy of this software and associated documentation files (the
103
+ 'Software'), to deal in the Software without restriction, including
104
+ without limitation the rights to use, copy, modify, merge, publish,
105
+ distribute, sublicense, and/or sell copies of the Software, and to
106
+ permit persons to whom the Software is furnished to do so, subject to
107
+ the following conditions:
108
+
109
+ The above copyright notice and this permission notice shall be
110
+ included in all copies or substantial portions of the Software.
111
+
112
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
113
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
114
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
115
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
116
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
117
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
118
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,64 @@
1
+ # -*- ruby -*-
2
+ $here = File.dirname(__FILE__)
3
+ require 'rubygems'
4
+ require "rake/testtask"
5
+ require 'spec/rake/spectask'
6
+ require "yard"
7
+
8
+ task :default => :test
9
+ task :test => [:spec, :examples]
10
+
11
+ # About yard documentation
12
+ YARD::Rake::YardocTask.new do |t|
13
+ t.files = ['lib/**/*.rb', 'examples/**/*.rb']
14
+ t.options = ['--output-dir', 'doc/api', '-', "README.md", "HISTORY.md"]
15
+ end
16
+
17
+ desc "Lauches unit tests on examples"
18
+ Rake::TestTask.new(:examples) do |test|
19
+ test.libs = [ "lib" ]
20
+ test.test_files = Dir["examples/**/*_test.rb"]
21
+ test.verbose = true
22
+ end
23
+
24
+ desc "Run all rspec test"
25
+ Spec::Rake::SpecTask.new(:spec) do |t|
26
+ t.ruby_opts = ['-I.', '-Ilib', '-Itest']
27
+ t.spec_files = Dir["#{$here}/test/**/*.spec"]
28
+ end
29
+
30
+ # PACKAGING & INSTALLATION ####################################################
31
+ # Largely inspired from the Citrus project
32
+
33
+ if defined?(Gem)
34
+ $spec = eval("#{File.read('quickl.gemspec')}")
35
+
36
+ directory 'dist'
37
+
38
+ def package(ext='')
39
+ "dist/#{$spec.name}-#{$spec.version}" + ext
40
+ end
41
+
42
+ file package('.gem') => %w< dist > + $spec.files do |f|
43
+ sh "gem build quickl.gemspec"
44
+ mv File.basename(f.name), f.name
45
+ end
46
+
47
+ file package('.tar.gz') => %w< dist > + $spec.files do |f|
48
+ sh "git archive --format=tar HEAD | gzip > #{f.name}"
49
+ end
50
+
51
+ desc "Build packages"
52
+ task :package => %w< .gem .tar.gz >.map {|e| package(e) }
53
+
54
+ desc "Build and install as local gem"
55
+ task :install => package('.gem') do |t|
56
+ sh "gem install #{package('.gem')}"
57
+ end
58
+
59
+ desc "Upload gem to rubygems.org"
60
+ task :release => package('.gem') do |t|
61
+ sh "gem push #{package('.gem')}"
62
+ end
63
+ end
64
+ # vim: syntax=ruby
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
3
+ require 'quickl'
4
+ require 'erb'
5
+
6
+ #
7
+ # Quickl - Generate Ruby command line apps quickly
8
+ #
9
+ # SYNOPSIS
10
+ # #{program_name} [options] COMMAND_NAME
11
+ #
12
+ # OPTIONS
13
+ # #{summarized_options}
14
+ #
15
+ # DESCRIPTION
16
+ # This tool helps you generating Ruby command line applications
17
+ #
18
+ class Quickl::Main < Quickl::Command(__FILE__, __LINE__)
19
+ include Quickl::Naming
20
+
21
+ OPTION_HELPERS = {
22
+ :version => %q{
23
+ opt.on_tail('--version', 'Show version and exit'){
24
+ raise Quickl::Exit, "#{program_name} #{VERSION}"
25
+ }
26
+ },
27
+ :help => %q{
28
+ opt.on_tail('--help', "Show this help message"){
29
+ raise Quickl::Help
30
+ }
31
+ }
32
+ }
33
+
34
+ # Name of the command to generate
35
+ attr_reader :cmd_name
36
+
37
+ # Creates a command instance
38
+ def initialize
39
+ @layout = :single
40
+ @gen_options = [:help, :version]
41
+ end
42
+
43
+ # Install options
44
+ options do |opt|
45
+
46
+ opt.on("--layout=LAYOUT", [:single],
47
+ "Select specific command layout (single)") do |l|
48
+ @layout = l
49
+ end
50
+
51
+ opt.on('--options x,y,z', Array,
52
+ "Automatically generate options for... (#{OPTION_HELPERS.keys.join(', ')})") do |list|
53
+ @gen_options = list.collect{|s| s.to_sym}
54
+ unless (unknown = @gen_options.reject{|s| OPTION_HELPERS.has_key?(s)}).empty?
55
+ raise Quickl::InvalidOption, "Unknown option helpers: #{unknown.join(',')}"
56
+ end
57
+ end
58
+
59
+ # Show the help and exit
60
+ opt.on_tail("--help", "Show help") do
61
+ raise Quickl::Help
62
+ end
63
+
64
+ # Show version and exit
65
+ opt.on_tail("--version", "Show version") do
66
+ raise Quickl::Exit, "#{program_name} #{Quickl::VERSION} #{Quickl::COPYRIGHT}"
67
+ end
68
+
69
+ end
70
+
71
+ # Loads template to use
72
+ def template
73
+ @template ||= File.expand_path("../../templates/#{@layout}.erb", __FILE__)
74
+ end
75
+
76
+ # Execute the command
77
+ def execute(args)
78
+ if args.size == 1
79
+ @cmd_name = args.shift
80
+ erb = ERB.new(File.read(template))
81
+ $stdout.puts erb.result(binding)
82
+ else
83
+ raise Quickl::InvalidArgument, "Invalid arguments: #{args.join(' ')}"
84
+ end
85
+ end
86
+
87
+ ### ERB scoping
88
+
89
+ # Class name of the command to generate
90
+ def cmd_class_name
91
+ command2module(cmd_name)
92
+ end
93
+
94
+ def indent(str, offset)
95
+ if offset >= 0
96
+ str.gsub(/^/, ' ' * offset)
97
+ else
98
+ str.gsub(/^ {0,#{-offset}}/, "")
99
+ end
100
+ end
101
+
102
+ def tabto(str, offset)
103
+ if str =~ /^( *)\S/
104
+ indent(str, offset - $1.length)
105
+ else
106
+ str
107
+ end
108
+ end
109
+
110
+ # Returns option helpers to include
111
+ def option_helpers
112
+ @gen_options.collect{|s| tabto(OPTION_HELPERS[s], 0).strip}
113
+ end
114
+
115
+ end # class Quickl::Command::Main
116
+ Quickl::Main.run(ARGV)
@@ -0,0 +1,86 @@
1
+ # Quickl example: delegate
2
+
3
+ This example shows how to delegate commands. Delegate commands are command
4
+ that delegate the actual execution to sub commands (well known example is
5
+ 'git'). A delegate command typically has a signature like:
6
+
7
+ delegate [main options] COMMAND [cmd options] ARGS...
8
+
9
+ ## Structure
10
+
11
+ The structure for delegate commands is as follows:
12
+
13
+ #
14
+ # Main command overview
15
+ #
16
+ # SYNOPSIS
17
+ # Usage: #{command_name} [main options] COMMAND [cmd options] ARGS...
18
+ #
19
+ # OPTIONS
20
+ # #{sumarized_options}
21
+ #
22
+ # COMMANDS
23
+ # #{summarized_commands}
24
+ #
25
+ # DESCRIPTION
26
+ # Long description here...
27
+ #
28
+ # See '#{command_name} help COMMAND' for more information on a specific command.
29
+ #
30
+ class DelegateCommand < Quickl::Delegate(__FILE__, __LINE__)
31
+
32
+ # install options below
33
+ options do |opt|
34
+ # _opt_ is an OptionParser instance
35
+ end
36
+
37
+ #
38
+ # Sub command overview
39
+ #
40
+ # ...
41
+ #
42
+ class SubCommand1 < Quickl::Command(__FILE__, __LINE__)
43
+
44
+ # [ ... ]
45
+
46
+ end
47
+
48
+ #
49
+ # Sub command overview
50
+ #
51
+ # ...
52
+ #
53
+ class SubCommand2 < Quickl::Command(__FILE__, __LINE__)
54
+
55
+ # [ ... ]
56
+
57
+ end
58
+
59
+ end
60
+
61
+ # To run the command, typically in a bin/simple_command
62
+ # shell file
63
+ DelegateCommand.run(ARGV)
64
+
65
+
66
+ ## Example
67
+
68
+ Try the following:
69
+
70
+ ./delegate
71
+ # => [ ... complete help with subcommands summary ... ]
72
+
73
+ ./delegate --help
74
+ # => [ ... complete help with subcommands summary ... ]
75
+
76
+ ./delegate help
77
+ # => [ ... complete help with subcommands summary ... ]
78
+
79
+ ./delegate help hello-world
80
+ # => [ ... help of hello-world's subcommand ... ]
81
+
82
+ ./delegate hello-world bob
83
+ # => Hello bob!
84
+
85
+ ./hello_world --capitalize bob
86
+ # => Hello Bob!
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../../../helper', __FILE__)
3
+
4
+ # Load the delegate tool
5
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
6
+ require "delegate"
7
+
8
+ # Run the command
9
+ Delegate.run(ARGV)
@@ -0,0 +1,41 @@
1
+ #
2
+ # Delegate execution to a sub command
3
+ #
4
+ # SYNOPSIS
5
+ # #{program_name} [--version] [--help] [--output=...] COMMAND [cmd opts] ARGS...
6
+ #
7
+ # OPTIONS
8
+ # #{summarized_options}
9
+ #
10
+ # COMMANDS
11
+ # #{summarized_subcommands}
12
+ #
13
+ # DESCRIPTION
14
+ # This example shows how to write a delegate command, that is, a
15
+ # command which delegates to a subcommand
16
+ #
17
+ # See '#{program_name} help COMMAND' for more information on a specific command.
18
+ #
19
+ class Delegate < Quickl::Delegate(__FILE__, __LINE__)
20
+
21
+ # Single command version
22
+ VERSION = "0.1.0"
23
+
24
+ # Install options
25
+ options do |opt|
26
+
27
+ # Show the help and exit
28
+ opt.on_tail("--help", "Show help") do
29
+ raise Quickl::Help
30
+ end
31
+
32
+ # Show version and exit
33
+ opt.on_tail("--version", "Show version") do
34
+ raise Quickl::Exit, "#{program_name} #{VERSION} (c) 2010, Bernard Lambeau"
35
+ end
36
+
37
+ end
38
+
39
+ end # class Delegate
40
+ require "help"
41
+ require "hello_world"