mothership 0.0.15 → 0.1.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.
@@ -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