mothership 0.0.15 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,12 +5,12 @@ class Mothership
5
5
  # all commands
6
6
  @@commands = {}
7
7
 
8
- # parsed global input set
9
- @@inputs = nil
8
+ attr_accessor :input
10
9
 
11
10
  # Initialize with the command being executed.
12
- def initialize(command = nil)
11
+ def initialize(command = nil, input = nil)
13
12
  @command = command
13
+ @input = input
14
14
  end
15
15
 
16
16
  class << self
@@ -41,8 +41,8 @@ class Mothership
41
41
  end
42
42
  end
43
43
 
44
- def execute(cmd, argv)
45
- cmd.invoke(Parser.new(cmd).inputs(argv))
44
+ def execute(cmd, argv, global = {})
45
+ cmd.invoke({}, Parser.new(cmd).parse_argv(argv), global)
46
46
  rescue Mothership::Error => e
47
47
  $stderr.puts e
48
48
  $stderr.puts ""
@@ -51,10 +51,16 @@ class Mothership
51
51
  exit_status 1
52
52
  end
53
53
 
54
+ # wrap this with your error handling/etc.
55
+ def run(name)
56
+ send(name)
57
+ end
58
+
54
59
  # invoke a command with inputs
55
- def invoke(name, inputs = {}, given = {})
60
+ def invoke(
61
+ name, inputs = {}, given = {}, global = @input ? @input.global : {})
56
62
  if cmd = @@commands[name]
57
- cmd.invoke(given, inputs)
63
+ cmd.invoke(inputs, given, global)
58
64
  else
59
65
  unknown_command(name)
60
66
  end
@@ -52,28 +52,30 @@ class Mothership
52
52
  str
53
53
  end
54
54
 
55
- def invoke(given, inputs = {})
55
+ def invoke(inputs = {}, given = {}, global = {})
56
56
  @before.each { |f, c| c.new.instance_exec(&f) }
57
57
 
58
58
  name = @name
59
59
  ctx = @context.new(self)
60
- input = Inputs.new(self, ctx, given, inputs)
60
+ ctx.input = Inputs.new(self, ctx, inputs, given, global)
61
61
 
62
62
  action = proc do |*given_inputs|
63
- ctx.send(name, given_inputs.first || input)
63
+ ctx.input = given_inputs.first || ctx.input
64
+ ctx.run(name)
64
65
  end
65
66
 
66
67
  cmd = self
67
68
  @around.each do |a, c|
68
69
  before = action
69
70
 
70
- sub = c.new(cmd)
71
+ sub = c.new(cmd, ctx.input)
71
72
  action = proc do |*given_inputs|
72
- sub.instance_exec(before, given_inputs.first || input, &a)
73
+ ctx.input = given_inputs.first || ctx.input
74
+ sub.instance_exec(before, ctx.input, &a)
73
75
  end
74
76
  end
75
77
 
76
- res = ctx.instance_exec(input, &action)
78
+ res = ctx.instance_exec(ctx.input, &action)
77
79
 
78
80
  @after.each { |f, c| c.new.instance_exec(&f) }
79
81
 
@@ -215,7 +215,7 @@ class Mothership
215
215
  desc "Help!"
216
216
  input :command, :argument => :optional
217
217
  input :all, :type => :boolean
218
- def help(input)
218
+ def help
219
219
  if name = input[:command]
220
220
  Mothership::Help.command_help(@@commands[name.gsub("-", "_").to_sym])
221
221
  elsif Help.has_groups?
@@ -1,12 +1,15 @@
1
1
  class Mothership
2
2
  class Inputs
3
- attr_reader :inputs
3
+ attr_reader :inputs, :given, :global
4
4
 
5
- def initialize(command, context = nil, given = {}, inputs = {})
5
+ def initialize(
6
+ command, context = nil,
7
+ inputs = {}, given = {}, global = {})
6
8
  @command = command
7
9
  @context = context
8
- @given = given
9
10
  @inputs = inputs
11
+ @given = given
12
+ @global = global
10
13
  end
11
14
 
12
15
  def given?(name)
@@ -14,15 +17,19 @@ class Mothership
14
17
  end
15
18
 
16
19
  def given(name)
17
- @inputs[name] || @given[name]
20
+ if @inputs.key?(name)
21
+ @inputs[name]
22
+ else
23
+ @given[name]
24
+ end
18
25
  end
19
26
 
20
27
  def merge(inputs)
21
- self.class.new(@command, @context, @given, @inputs.merge(inputs))
28
+ self.class.new(@command, @context, @inputs.merge(inputs), @given)
22
29
  end
23
30
 
24
31
  def merge_given(inputs)
25
- self.class.new(@command, @context, @given.merge(inputs), @inputs)
32
+ self.class.new(@command, @context, @inputs, @given.merge(inputs))
26
33
  end
27
34
 
28
35
  def without(*names)
@@ -40,31 +47,32 @@ class Mothership
40
47
  get(name, @context, *args)
41
48
  end
42
49
 
50
+ # search:
51
+ # 1. cache
52
+ # 2. cache, singular
53
+ # 3. given
54
+ # 4. given, singular
55
+ # 5. global
56
+ # 6. global, singular
43
57
  def get(name, context, *args)
44
58
  return @inputs[name] if @inputs.key?(name)
45
59
 
46
- meta = @command.inputs[name]
47
- return unless meta
60
+ if meta = @command.inputs[name]
61
+ # special case so #invoke can be called with singular-named inputs
62
+ singular = meta[:singular]
63
+ return @inputs[name] = [@inputs[singular]] if @inputs.key?(singular)
48
64
 
49
- singular = meta[:singular]
50
- return @inputs[name] = [@inputs[singular]] if @inputs.key?(singular)
51
-
52
- given = @given[name] if @given.key?(name)
53
- given ||= [@given[singular]] if @given.key?(singular)
54
-
55
- # value given; convert if needed
56
- if given && given != []
57
- return @inputs[name] = convert_given(meta, context, given, *args)
65
+ found, val = find_in(@given, name, meta, context, *args)
58
66
  end
59
67
 
60
- # no value given; set as default
61
- val = default_for(meta, context, *args)
62
-
63
- unless meta[:forget]
64
- @inputs[name] = val
68
+ # if not found locally and the default is nil, search globally
69
+ if !found && val.nil? && meta = Mothership.global_option(name)
70
+ found, val = find_in(@global, name, meta, context, *args)
65
71
  end
66
72
 
67
- val
73
+ return val if not found
74
+
75
+ @inputs[name] = convert_given(meta, context, val, *args)
68
76
  end
69
77
 
70
78
  def forget(name)
@@ -74,6 +82,24 @@ class Mothership
74
82
 
75
83
  private
76
84
 
85
+ def find_in(where, name, meta, context, *args)
86
+ singular = meta[:singular]
87
+
88
+ if where.key?(name)
89
+ [true, where[name]]
90
+ elsif where.key?(singular)
91
+ [true, [where[singular]]]
92
+ else
93
+ # no value given; set as default
94
+ val = default_for(meta, context, *args)
95
+
96
+ # cache default value
97
+ @inputs[name] = val unless meta[:forget]
98
+
99
+ [false, val]
100
+ end
101
+ end
102
+
77
103
  def convert_given(meta, context, given, *args)
78
104
  if convert = meta[:from_given]
79
105
  if given.is_a?(Array)
@@ -1,20 +1,21 @@
1
1
  class Mothership
2
2
  class Parser
3
- def initialize(command)
3
+ attr_reader :given
4
+
5
+ def initialize(command, given = {})
4
6
  @command = command
7
+ @given = given
5
8
  end
6
9
 
7
- def inputs(argv)
8
- inputs = {}
9
-
10
- args = parse_flags(inputs, argv.dup)
10
+ def parse_argv(argv)
11
+ args = parse_flags(argv.dup)
11
12
 
12
- parse_arguments(inputs, args)
13
+ parse_arguments(args)
13
14
 
14
- inputs
15
+ @given
15
16
  end
16
17
 
17
- def parse_flags(inputs, argv, find_in = nil)
18
+ def parse_flags(argv, find_in = nil)
18
19
  local = nil
19
20
  args = []
20
21
 
@@ -43,19 +44,19 @@ class Mothership
43
44
  case input[:type]
44
45
  when :bool, :boolean
45
46
  if argv.first == "false" || argv.first == "true"
46
- inputs[name] = argv.shift == "true"
47
+ @given[name] = argv.shift == "true"
47
48
  else
48
- inputs[name] = true
49
+ @given[name] = true
49
50
  end
50
51
  when :float, :floating
51
52
  if !argv.empty? && argv.first =~ /^[0-9]+(\.[0-9]*)?$/
52
- inputs[name] = argv.shift.to_f
53
+ @given[name] = argv.shift.to_f
53
54
  else
54
55
  raise TypeMismatch.new(@command.name, name, "floating")
55
56
  end
56
57
  when :integer, :number, :numeric
57
58
  if !argv.empty? && argv.first =~ /^[0-9]+$/
58
- inputs[name] = argv.shift.to_i
59
+ @given[name] = argv.shift.to_i
59
60
  else
60
61
  raise TypeMismatch.new(@command.name, name, "numeric")
61
62
  end
@@ -63,7 +64,7 @@ class Mothership
63
64
  if argv.empty? || !argv.first.start_with?("-")
64
65
  arg = argv.shift || ""
65
66
 
66
- inputs[name] =
67
+ @given[name] =
67
68
  if input[:argument] == :splat
68
69
  arg.split(",")
69
70
  else
@@ -80,7 +81,7 @@ class Mothership
80
81
  # 1 2 => :fizz => 1, :buzz => 2
81
82
  # 1 2 3 => :foo => 1, :fizz => 2, :buzz => 3
82
83
  # 1 2 3 4 => :foo => 1, :bar => 2, :fizz => 3, :buzz => 4
83
- def parse_arguments(inputs, args)
84
+ def parse_arguments(args)
84
85
  total = @command.arguments.size
85
86
  required = 0
86
87
  optional = 0
@@ -99,25 +100,25 @@ class Mothership
99
100
 
100
101
  @command.arguments.each do |arg|
101
102
  name = arg[:name]
102
- next if inputs.key? name
103
+ next if @given.key? name
103
104
 
104
105
  case arg[:type]
105
106
  when :splat
106
- inputs[name] = []
107
+ @given[name] = []
107
108
 
108
109
  until args.empty?
109
- inputs[name] << args.shift
110
+ @given[name] << args.shift
110
111
  end
111
112
 
112
113
  when :optional
113
114
  if parse_optionals > 0 && val = args.shift
114
- inputs[name] = val
115
+ @given[name] = val
115
116
  parse_optionals -= 1
116
117
  end
117
118
 
118
119
  else
119
120
  if val = args.shift
120
- inputs[name] = val
121
+ @given[name] = val
121
122
  elsif !@command.inputs[name][:default]
122
123
  raise MissingArgument.new(@command.name, name)
123
124
  end
@@ -1,3 +1,3 @@
1
1
  class Mothership
2
- VERSION = "0.0.15"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/mothership.rb CHANGED
@@ -9,9 +9,6 @@ class Mothership
9
9
  # [Mothership::Command] global options
10
10
  @@global = Command.new(self, "(global options)")
11
11
 
12
- # [Mothershp::Inputs] inputs from global options
13
- @@inputs = Inputs.new(@@global)
14
-
15
12
  # [Fixnum] exit status; reassign as appropriate error code (e.g. 1)
16
13
  @@exit_status = 0
17
14
 
@@ -27,11 +24,8 @@ class Mothership
27
24
  # arguments and flags can be in any order; all flags will be parsed out
28
25
  # first, and the bits left over will be treated as arguments
29
26
  def start(argv)
30
- name, *argv =
31
- Parser.new(@@global).parse_flags(
32
- @@inputs.inputs,
33
- argv,
34
- @@commands)
27
+ global_parser = Parser.new(@@global)
28
+ name, *argv = global_parser.parse_flags(argv, @@commands)
35
29
 
36
30
  app = new
37
31
 
@@ -42,7 +36,7 @@ class Mothership
42
36
  cmd = @@commands[cmdname]
43
37
  return app.unknown_command(cmdname) unless cmd
44
38
 
45
- app.execute(cmd, argv)
39
+ app.execute(cmd, argv, global_parser.given)
46
40
 
47
41
  code = @@exit_status
48
42
 
@@ -51,20 +45,14 @@ class Mothership
51
45
 
52
46
  exit code
53
47
  end
48
+
49
+ def global_option(name)
50
+ @@global.inputs[name]
51
+ end
54
52
  end
55
53
 
56
54
  # set the exit status
57
55
  def exit_status(num)
58
56
  @@exit_status = num
59
57
  end
60
-
61
- # get value of global option
62
- def option(name, *args)
63
- @@inputs.get(name, self, *args)
64
- end
65
-
66
- # test if an option was explicitly provided
67
- def option_given?(name)
68
- @@inputs.given? name
69
- end
70
58
  end
data/spec/helpers.rb CHANGED
@@ -14,7 +14,7 @@ module MothershipHelpers
14
14
  end
15
15
 
16
16
  def inputs(cmd, *argv)
17
- Mothership::Parser.new(cmd).inputs(argv)
17
+ Mothership::Parser.new(cmd).parse_argv(argv)
18
18
  end
19
19
  end
20
20
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mothership
3
3
  version: !ruby/object:Gem::Version
4
- hash: 1
4
+ hash: 27
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
+ - 1
8
9
  - 0
9
- - 15
10
- version: 0.0.15
10
+ version: 0.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Alex Suraci
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-08-21 00:00:00 Z
18
+ date: 2012-08-22 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: rake