climate 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/climate.rb CHANGED
@@ -40,8 +40,6 @@ module Climate
40
40
  end
41
41
 
42
42
  require 'climate/errors'
43
- require 'climate/argument'
44
- require 'climate/option'
45
43
  require 'climate/parser'
46
44
  require 'climate/command'
47
45
  require 'climate/help'
@@ -14,11 +14,11 @@ module Climate
14
14
 
15
15
  # Create an instance of this command class and run it against the given
16
16
  # arguments
17
- # @param [Array<String>] arguments A list of arguments, ARGV style
17
+ # @param [Array<String>] argv A list of arguments, ARGV style
18
18
  # @param [Hash] options see {#initialize}
19
- def run(arguments, options={})
19
+ def run(argv, options={})
20
20
  begin
21
- instance = new(arguments, options)
21
+ instance = new(argv, options)
22
22
  rescue Trollop::HelpNeeded
23
23
  raise HelpNeeded.new(self)
24
24
  end
@@ -47,6 +47,13 @@ module Climate
47
47
  @name
48
48
  end
49
49
 
50
+ # because we've extended Class.name, we expose the original method
51
+ # under another name
52
+ # FIXME: surely there is a saner way of doing this?
53
+ def class_name
54
+ Class.method(:name).unbind.bind(self).call
55
+ end
56
+
50
57
  # Register this class as being a subcommand of another {Command} class
51
58
  # @param [Command] parent_class The parent we hang off of
52
59
  def subcommand_of(parent_class)
@@ -64,6 +71,15 @@ module Climate
64
71
  end
65
72
  end
66
73
 
74
+ # Call this during class definition time if you don't want any of the
75
+ # usual command line parsing to happen
76
+ def disable_parsing
77
+ @parsing_disabled = true
78
+ end
79
+
80
+ # Returns true if parsing is disabled
81
+ attr_accessor :parsing_disabled
82
+
67
83
  # Set the parent of this command
68
84
  attr_accessor :parent
69
85
 
@@ -116,16 +132,24 @@ module Climate
116
132
  # @option options [IO] :stdout stream to use as stdout, defaulting to `$stdout`
117
133
  # @option options [IO] :stderr stream to use as stderr, defaulting to `$stderr`
118
134
  # @option options [IO] :stdin stream to use as stdin, defaulting to `$stdin`
119
- def initialize(arguments, options={})
135
+ def initialize(argv, options={})
136
+ @argv = argv.clone
120
137
  @parent = options[:parent]
121
138
 
122
139
  @stdout = options[:stdout] || $stdout
123
140
  @stderr = options[:stderr] || $stderr
124
141
  @stdin = options[:stdin] || $stdin
125
142
 
126
- @arguments, @options, @leftovers = self.class.parse(arguments)
143
+ if ! self.class.parsing_disabled
144
+ @arguments, @options, @leftovers = self.class.parse(argv)
145
+ end
127
146
  end
128
147
 
148
+ # @return [Array]
149
+ # The original list of unparsed argv style arguments that were given to
150
+ # the command
151
+ attr_accessor :argv
152
+
129
153
  # @return [Hash]
130
154
  # Options that were parsed from the command line
131
155
  attr_accessor :options
@@ -156,5 +180,11 @@ module Climate
156
180
  parent.ancestor(ancestor_class)
157
181
  end
158
182
  end
183
+
184
+ # Run the command, must be implemented by all commands that are not parent
185
+ # commands (leaf commands)
186
+ def run
187
+ raise NotImplementedError, "Leaf commands must implement a run method"
188
+ end
159
189
  end
160
190
  end
data/lib/climate/help.rb CHANGED
@@ -101,7 +101,7 @@ module Climate
101
101
  end
102
102
 
103
103
  def puts(string='')
104
- string.split("\n").each do |line|
104
+ wrap(string).split("\n").each do |line|
105
105
  @output.puts((' ' * spaces) + line)
106
106
  end
107
107
  end
@@ -129,7 +129,7 @@ module Climate
129
129
 
130
130
  string.split("\n\n").map { |para|
131
131
 
132
- words = para.split(/[\n ]/)
132
+ words = para.split(/[\n ]+/)
133
133
  words[1..-1].inject([words.first]) { |m, v|
134
134
  new_last_line = m.last + " " + v
135
135
 
@@ -1,9 +1,97 @@
1
1
  module Climate
2
2
 
3
+ # Keeps the description munging code in one place
4
+ module Described
5
+ attr_reader :name
6
+
7
+ def initialize(name, description, *rest)
8
+ @name = name
9
+ @description = description
10
+ end
11
+
12
+ def description
13
+ (@description || '').gsub(/\{default\}/, default.to_s)
14
+ end
15
+ end
16
+
17
+ # Wraps the properties supplied to Trollop::Parser#opt for some OO over
18
+ # engineered sweetness
19
+ class Option
20
+ include Described
21
+ attr_reader :options
22
+
23
+ def initialize(name, description, options={})
24
+ @options = options
25
+ super
26
+ end
27
+
28
+ def type ; spec[:type] ; end
29
+ def long ; spec[:long] ; end
30
+ def short ; spec[:short] ; end
31
+ def default ; spec[:default] ; end
32
+
33
+ def optional? ; spec.has_key?(:default) ; end
34
+ def required? ; ! optional? ; end
35
+
36
+ def spec ; @specs ||= parser.specs[@name] ; end
37
+
38
+ def parser
39
+ @parser ||= Trollop::Parser.new.tap {|p| add_to(p) }
40
+ end
41
+
42
+ def long_usage
43
+ type == :flag ? "--#{long}" : "--#{long}=<#{type}>"
44
+ end
45
+
46
+ def short_usage
47
+ short && (type == :flag ? "-#{short}" : "-#{short}<#{type}>")
48
+ end
49
+
50
+ def usage(options={})
51
+ help = short_usage || long_usage
52
+
53
+ if options[:with_long] && (long_usage != help)
54
+ help = [help, long_usage].compact.join(options.fetch(:separator, '|'))
55
+ end
56
+
57
+ if optional? && !options.fetch(:hide_optional, false)
58
+ "[#{help}]"
59
+ else
60
+ help
61
+ end
62
+ end
63
+
64
+ def add_to(parser)
65
+ parser.opt(@name, @description, @options)
66
+ end
67
+ end
68
+
69
+ # argument definition is stored in these
70
+ class Argument
71
+ include Described
72
+ attr_reader :default
73
+
74
+ def initialize(name, description, options={})
75
+ super
76
+ @required = options.fetch(:required, ! options.has_key?(:default))
77
+ @multi = options.fetch(:multi, false)
78
+ @default = options.fetch(:default, nil)
79
+ end
80
+
81
+ def required? ; @required ; end
82
+ def optional? ; ! required? ; end
83
+ def multi? ; @multi ; end
84
+
85
+ def usage
86
+ string = "<#{name}>"
87
+ string += '...' if multi?
88
+ optional?? "[#{string}]" : string
89
+ end
90
+ end
91
+
3
92
  module ParsingMethods
4
93
 
5
94
  def arg(*args)
6
-
7
95
  arg = Argument.new(*args)
8
96
 
9
97
  raise DefinitionError, "can not define more arguments after a multi " +
@@ -24,27 +112,13 @@ module Climate
24
112
  end
25
113
 
26
114
  def trollop_parser
27
- parser = Trollop::Parser.new
28
-
29
- parser.stop_on @stop_on
115
+ Trollop::Parser.new.tap do |parser|
116
+ parser.stop_on @stop_on
30
117
 
31
- if cli_arguments.size > 0
32
- parser.banner ""
33
- max_length = cli_arguments.map { |h| h.name.to_s.length }.max
34
- cli_arguments.each do |argument|
35
- parser.banner(" " + argument.name.to_s.rjust(max_length) + " - #{argument.description}")
118
+ cli_options.each do |option|
119
+ option.add_to(parser)
36
120
  end
37
121
  end
38
-
39
- parser.banner ""
40
- cli_options.each do |option|
41
- option.add_to(parser)
42
- end
43
- parser
44
- end
45
-
46
- def help_banner(out=$stdout)
47
- trollop_parser.educate(out)
48
122
  end
49
123
 
50
124
  def parse_arguments(args, command=self)
@@ -69,7 +143,7 @@ module Climate
69
143
  end
70
144
 
71
145
  arg_list.zip(args).map do |argument, arg_value|
72
-
146
+ arg_value ||= argument.default
73
147
  if argument.required? && arg_value.nil?
74
148
  raise MissingArgumentError.new(argument.name, command)
75
149
  end
@@ -1,3 +1,3 @@
1
1
  module Climate
2
- VERSION = '0.2.0'
2
+ VERSION = '0.3.0'
3
3
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: climate
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 2
8
+ - 3
9
9
  - 0
10
- version: 0.2.0
10
+ version: 0.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Nick Griffiths
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-07-23 00:00:00 Z
18
+ date: 2012-08-08 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: trollop
@@ -85,9 +85,7 @@ extra_rdoc_files: []
85
85
  files:
86
86
  - lib/climate/version.rb
87
87
  - lib/climate/help/man.rb
88
- - lib/climate/argument.rb
89
88
  - lib/climate/command.rb
90
- - lib/climate/option.rb
91
89
  - lib/climate/parser.rb
92
90
  - lib/climate/errors.rb
93
91
  - lib/climate/script.rb
@@ -1,28 +0,0 @@
1
- module Climate
2
- class Argument
3
-
4
- attr_reader :name
5
- attr_reader :description
6
-
7
- def initialize(name, description, options={})
8
- @name = name
9
- @description = description
10
- @required = options.fetch(:required, true)
11
- @multi = options.fetch(:multi, false)
12
- end
13
-
14
- def required? ; @required ; end
15
- def optional? ; ! required? ; end
16
- def multi? ; @multi ; end
17
-
18
- def usage
19
- string = "<#{name}>"
20
- string += '...' if multi?
21
- optional?? "[#{string}]" : string
22
- end
23
-
24
- def formatted
25
- required?? name.to_s.upcase : "[#{name.to_s.upcase}]"
26
- end
27
- end
28
- end
@@ -1,54 +0,0 @@
1
- module Climate
2
- class Option
3
-
4
- attr_reader :name
5
- attr_reader :description
6
- attr_reader :options
7
-
8
- def initialize(name, description, options={})
9
- @name = name
10
- @description = description
11
- @options = options
12
- end
13
-
14
- def type ; spec[:type] ; end
15
- def long ; spec[:long] ; end
16
- def short ; spec[:short] ; end
17
- def default ; spec[:default] ; end
18
-
19
- def optional? ; spec.has_key?(:default) ; end
20
- def required? ; ! optional? ; end
21
-
22
- def spec ; @specs ||= parser.specs[@name] ; end
23
-
24
- def parser
25
- @parser ||= Trollop::Parser.new.tap {|p| add_to(p) }
26
- end
27
-
28
- def long_usage
29
- type == :flag ? "--#{long}" : "--#{long}=<#{type}>"
30
- end
31
-
32
- def short_usage
33
- short && (type == :flag ? "-#{short}" : "-#{short}<#{type}>")
34
- end
35
-
36
- def usage(options={})
37
- help = short_usage || long_usage
38
-
39
- if options[:with_long] && (long_usage != help)
40
- help = [help, long_usage].compact.join(options.fetch(:separator, '|'))
41
- end
42
-
43
- if optional? && !options.fetch(:hide_optional, false)
44
- "[#{help}]"
45
- else
46
- help
47
- end
48
- end
49
-
50
- def add_to(parser)
51
- parser.opt(@name, @description, @options)
52
- end
53
- end
54
- end