menutree 0.0.4 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1 +1 @@
1
- pkg/
1
+ *.gem
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Menutree
2
2
 
3
- Menutree is a framework for presenting a recursive menu shell on the command
3
+ Menutree is a framework for presenting a recursive Read-Eval-Print Loop (REPL) shell on the command
4
4
  line, inspired by the CLI found in Cisco IOS and other similar products.
5
5
  Menutree lets users issue commands via an interactive nested shell interface,
6
6
  and also directly from the command line.
@@ -11,26 +11,24 @@ readline support are all built in.
11
11
 
12
12
  ## Example:
13
13
 
14
- Given a hypothetical program 'ticker' that uses the Menutree gem to manage a list of
15
- tickets, a sample interaction might look like:
14
+ Given a hypothetical program 'ticket' that uses the Menutree gem to manage a list of
15
+ tickets (such a program is included in `examples/`), a sample interaction might look like:
16
16
 
17
17
  <pre>
18
- $ ticker
19
- > init
20
- Ticker created an empty ticket database
21
- > add "Do a little dance"
22
- Ticket "Do a little dance" added as ticket 213
23
- > rm
24
- rm> 213
25
- Ticket 213 ("Do a little dance") removed
26
- rm> ..
18
+ $ ruby ticket.rb
19
+ > action_one
20
+ One
21
+ > submenu_one
22
+ /submenu_one> action_one
23
+ Unknown command 'action_one'
24
+ /submenu_one> ..
27
25
  > exit
28
26
  </pre>
29
27
 
30
28
  Commands could also be run from the shell:
31
29
 
32
30
  <pre>
33
- $ ticker add "Make a little love"
31
+ $ rubyticke add "Make a little love"
34
32
  Ticket "Make a little love" added as ticket 214
35
33
  </pre>
36
34
 
data/Rakefile CHANGED
@@ -2,23 +2,6 @@ require 'rake'
2
2
  require 'rake/testtask'
3
3
  require 'rcov/rcovtask'
4
4
 
5
- begin
6
- require 'jeweler'
7
- Jeweler::Tasks.new do |s|
8
- s.name = "menutree"
9
- s.summary = "a simple hierachical command line shell"
10
- s.description = "Menutree is a framework for presenting a recursive menu shell on the command
11
- line, inspired by the CLI found in Cisco IOS and similar products"
12
- s.email = "mat@geeky.net"
13
- s.homepage = "http://github.com/mtrudel/menutree"
14
- s.authors = ["Mat Trudel", "Grant McInnes"]
15
- s.add_dependency 'activesupport'
16
- end
17
- Jeweler::GemcutterTasks.new
18
- rescue LoadError
19
- puts "Jeweler not available. Install it with: gem install jeweler"
20
- end
21
-
22
5
  Rake::TestTask.new do |t|
23
6
  t.libs << 'lib'
24
7
  t.pattern = 'test/**/*_test.rb'
@@ -0,0 +1,11 @@
1
+ leaf do |tree|
2
+ desc "This is action one's help"
3
+ def action_one(*args)
4
+ puts "This is action one, called with: #{args.join ' '}"
5
+ end
6
+
7
+ desc "This is action two's help"
8
+ def action_two(*args)
9
+ puts "This is action two, called with: #{args.join ' '}"
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ leaf do |tree|
2
+ desc "This is action one's help inside submenu one"
3
+ def action_one(*args)
4
+ puts "This is action one in submenu one, called with: #{args.join ' '}"
5
+ end
6
+
7
+ desc "This is action two's help inside submenu one"
8
+ def action_two(*args)
9
+ puts "This is action two in submenu one, called with: #{args.join ' '}"
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ leaf do |tree|
2
+ desc "This is action one's help inside submenu two"
3
+ def action_one(*args)
4
+ puts "This is action one in submenu two, called with: #{args.join ' '}"
5
+ end
6
+
7
+ desc "This is action two's help inside submenu one"
8
+ def action_two(*args)
9
+ puts "This is action two in submenu two, called with: #{args.join ' '}"
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'menutree'
5
+
6
+ MenuTree::Tree.new(File.join(File.dirname(__FILE__), 'commands')).repl(ARGV)
@@ -1,5 +1,5 @@
1
- $:.unshift(File.dirname(__FILE__)) unless
2
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
1
+ $:.unshift(File.join(File.dirname(__FILE__), 'menutree')) unless
2
+ $:.include?(File.join(File.dirname(__FILE__), 'menutree')) || $:.include?(File.expand_path(File.join(File.dirname(__FILE__), 'menutree')))
3
3
 
4
- require 'base'
4
+ require 'tree'
5
5
 
@@ -0,0 +1,26 @@
1
+ module MenuTree
2
+ INDENT = "\t"
3
+ COMMAND_WIDTH = -12
4
+ BUILTINS = {
5
+ "help" => "Displays this message",
6
+ "quit" => "Quits this session",
7
+ ".." => "Goes up a level in the menu (or quits if at the root)",
8
+ }
9
+
10
+ module Help
11
+ def display_help
12
+ display_help_section("Built-in commands", BUILTINS)
13
+ display_help_section("Leaf commands", @leaf.commands)
14
+ display_help_section("Submenus", submenus)
15
+ end
16
+
17
+ def display_help_section(section, contents, indent = 0)
18
+ puts INDENT*indent + section
19
+ contents.each do |command, description|
20
+ puts INDENT*(indent+1) + sprintf("%#{COMMAND_WIDTH}s %s", command, description)
21
+ end
22
+ puts ""
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,23 @@
1
+ module MenuTree
2
+ class Leaf
3
+ attr_accessor :commands
4
+
5
+ def initialize(parent_tree)
6
+ @parent_tree = parent_tree
7
+ @commands = {}
8
+ @curent_description = ""
9
+ end
10
+
11
+ def desc(desc)
12
+ @current_description = desc
13
+ end
14
+
15
+ def singleton_method_added(symbol)
16
+ @commands[symbol] = @current_description
17
+ end
18
+
19
+ def leaf(&block)
20
+ self.instance_exec(@parent_tree, &block) if block_given?
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,73 @@
1
+ require 'readline'
2
+ require 'active_support'
3
+ require 'leaf'
4
+ require 'help'
5
+
6
+ module MenuTree
7
+ class Tree
8
+ include Help
9
+ attr_accessor :directory
10
+ attr_accessor :prompt
11
+ attr_accessor :leaf
12
+
13
+ def initialize(directory, parent = "")
14
+ @directory = directory
15
+ if parent.is_a? String
16
+ @prompt = parent
17
+ elsif !parent.prompt.empty?
18
+ @prompt = parent.prompt + "/" + File.basename(@directory)
19
+ else
20
+ @prompt = File.basename(@directory)
21
+ end
22
+
23
+ file = File.join(@directory, "leaf.rb")
24
+ @leaf = MenuTree::Leaf.new(self)
25
+ @leaf.instance_eval(File.read(file), file) if File.exists? file
26
+ end
27
+
28
+ def repl(cmds)
29
+ one_shot = true unless cmds.empty?
30
+ to_run = cmds.shift
31
+ while true do
32
+ Readline.completion_append_character = " "
33
+ Readline.completion_proc = Proc.new do |str|
34
+ commands(str)
35
+ end
36
+ if (to_run.nil?)
37
+ cmds = Readline.readline("#{@prompt}> ", true).split
38
+ to_run = cmds.shift
39
+ end
40
+
41
+ # If it's a builtin, run it
42
+ if (to_run.nil?)
43
+ next
44
+ elsif (to_run == "help" or to_run == "?")
45
+ display_help
46
+ elsif (to_run == "quit")
47
+ exit
48
+ elsif (to_run == "..")
49
+ return
50
+ elsif File.directory?(File.join(@directory, to_run))
51
+ menu = MenuTree::Tree.new(File.join(@directory, to_run), self)
52
+ menu.repl(cmds)
53
+ else
54
+ @leaf.send to_run, cmds rescue puts "Unknown command #{to_run}"
55
+ end
56
+ to_run = nil
57
+ return if one_shot
58
+ end
59
+ end
60
+
61
+ def commands(prefix='')
62
+ (leaf_commands + submenus).select { |command| command =~ /^#{Regexp.escape(prefix)}/ }
63
+ end
64
+
65
+ def leaf_commands
66
+ @leaf.commands.keys.map { |x| x.to_s }
67
+ end
68
+
69
+ def submenus
70
+ Dir.new(@directory).select { |entry| entry =~ /^[^\.]/ and File.directory?(File.join(@directory, entry)) }
71
+ end
72
+ end
73
+ end
@@ -1,17 +1,10 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in rakefile, and run the gemspec command
4
- # -*- encoding: utf-8 -*-
5
-
6
1
  Gem::Specification.new do |s|
7
2
  s.name = %q{menutree}
8
- s.version = "0.0.4"
3
+ s.version = "0.1.1"
9
4
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
5
  s.authors = ["Mat Trudel", "Grant McInnes"]
12
- s.date = %q{2010-03-16}
13
- s.description = %q{Menutree is a framework for presenting a recursive menu shell on the command
14
- line, inspired by the CLI found in Cisco IOS and similar products}
6
+ s.date = %q{2011-01-05}
7
+ s.description = %q{Menutree is a framework for presenting a recursive REPL shell, inspired by the CLI found in Cisco IOS and similar products}
15
8
  s.email = %q{mat@geeky.net}
16
9
  s.extra_rdoc_files = [
17
10
  "README.md"
@@ -20,28 +13,19 @@ Gem::Specification.new do |s|
20
13
  ".gitignore",
21
14
  "README.md",
22
15
  "Rakefile",
23
- "VERSION",
24
- "lib/base.rb",
25
16
  "lib/menutree.rb",
17
+ "lib/menutree/tree.rb",
18
+ "lib/menutree/leaf.rb",
19
+ "lib/menutree/help.rb",
20
+ "examples/example.rb",
21
+ "examples/commands/leaf.rb",
22
+ "examples/commands/submenu_one/leaf.rb",
23
+ "examples/commands/submenu_two/leaf.rb",
26
24
  "menutree.gemspec"
27
25
  ]
28
26
  s.homepage = %q{http://github.com/mtrudel/menutree}
29
- s.rdoc_options = ["--charset=UTF-8"]
30
27
  s.require_paths = ["lib"]
31
- s.rubygems_version = %q{1.3.6}
32
- s.summary = %q{a simple hierachical command line shell}
33
-
34
- if s.respond_to? :specification_version then
35
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
36
- s.specification_version = 3
37
-
38
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
39
- s.add_runtime_dependency(%q<activesupport>, [">= 0"])
40
- else
41
- s.add_dependency(%q<activesupport>, [">= 0"])
42
- end
43
- else
44
- s.add_dependency(%q<activesupport>, [">= 0"])
45
- end
28
+ s.summary = %q{a simple hierachical REPL shell}
29
+ s.add_dependency(%q<activesupport>, [">= 0"])
46
30
  end
47
31
 
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: menutree
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 25
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
- - 0
8
- - 4
9
- version: 0.0.4
8
+ - 1
9
+ - 1
10
+ version: 0.1.1
10
11
  platform: ruby
11
12
  authors:
12
13
  - Mat Trudel
@@ -15,24 +16,24 @@ autorequire:
15
16
  bindir: bin
16
17
  cert_chain: []
17
18
 
18
- date: 2010-03-16 00:00:00 -04:00
19
+ date: 2011-01-05 00:00:00 -05:00
19
20
  default_executable:
20
21
  dependencies:
21
22
  - !ruby/object:Gem::Dependency
22
23
  name: activesupport
23
24
  prerelease: false
24
25
  requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
25
27
  requirements:
26
28
  - - ">="
27
29
  - !ruby/object:Gem::Version
30
+ hash: 3
28
31
  segments:
29
32
  - 0
30
33
  version: "0"
31
34
  type: :runtime
32
35
  version_requirements: *id001
33
- description: |-
34
- Menutree is a framework for presenting a recursive menu shell on the command
35
- line, inspired by the CLI found in Cisco IOS and similar products
36
+ description: Menutree is a framework for presenting a recursive REPL shell, inspired by the CLI found in Cisco IOS and similar products
36
37
  email: mat@geeky.net
37
38
  executables: []
38
39
 
@@ -44,39 +45,48 @@ files:
44
45
  - .gitignore
45
46
  - README.md
46
47
  - Rakefile
47
- - VERSION
48
- - lib/base.rb
49
48
  - lib/menutree.rb
49
+ - lib/menutree/tree.rb
50
+ - lib/menutree/leaf.rb
51
+ - lib/menutree/help.rb
52
+ - examples/example.rb
53
+ - examples/commands/leaf.rb
54
+ - examples/commands/submenu_one/leaf.rb
55
+ - examples/commands/submenu_two/leaf.rb
50
56
  - menutree.gemspec
51
57
  has_rdoc: true
52
58
  homepage: http://github.com/mtrudel/menutree
53
59
  licenses: []
54
60
 
55
61
  post_install_message:
56
- rdoc_options:
57
- - --charset=UTF-8
62
+ rdoc_options: []
63
+
58
64
  require_paths:
59
65
  - lib
60
66
  required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
61
68
  requirements:
62
69
  - - ">="
63
70
  - !ruby/object:Gem::Version
71
+ hash: 3
64
72
  segments:
65
73
  - 0
66
74
  version: "0"
67
75
  required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
68
77
  requirements:
69
78
  - - ">="
70
79
  - !ruby/object:Gem::Version
80
+ hash: 3
71
81
  segments:
72
82
  - 0
73
83
  version: "0"
74
84
  requirements: []
75
85
 
76
86
  rubyforge_project:
77
- rubygems_version: 1.3.6
87
+ rubygems_version: 1.3.7
78
88
  signing_key:
79
89
  specification_version: 3
80
- summary: a simple hierachical command line shell
90
+ summary: a simple hierachical REPL shell
81
91
  test_files: []
82
92
 
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.0.4
@@ -1,86 +0,0 @@
1
- require 'readline'
2
- require 'active_support'
3
-
4
- class MenuTree
5
- attr_accessor :directory
6
- attr_accessor :parent
7
- attr_accessor :prompt
8
-
9
- def initialize(directory, parent = "")
10
- @directory = directory
11
- @parent = parent
12
- if @parent.is_a? self.class
13
- @prompt = @parent.prompt + "/" + File.basename(@directory)
14
- else
15
- @prompt = @parent
16
- end
17
- end
18
-
19
- def run_command(cmds)
20
- Readline.completion_append_character = " "
21
- Readline.completion_proc = Proc.new do |str|
22
- commands(str)
23
- end
24
-
25
- one_shot = true unless cmds.empty?
26
- to_run = cmds.shift
27
- while true do
28
- if (to_run.nil?)
29
- cmds = Readline.readline("#{@prompt}> ", true).split
30
- to_run = cmds.shift
31
- end
32
-
33
- # If it's a builtin, run it
34
- if (to_run.nil?)
35
- next
36
- elsif (to_run == "help" or to_run == "?")
37
- display_help
38
- elsif (to_run == "quit")
39
- exit
40
- elsif (to_run == "..")
41
- return
42
- elsif File.exists?(File.join(@directory, "#{to_run}.rb"))
43
- # If we have a .rb file, run it with the rest of cmd as arguments
44
- # TODO -- use .extend?
45
- require File.join(@directory, "#{to_run}")
46
- eval(to_run.camelize).new.run(cmds)
47
- elsif File.directory?(File.join(@directory, to_run))
48
- menu = MenuTree.new(File.join(@directory, to_run), self)
49
- menu.run_command(cmds)
50
- elsif File.exists?(File.join(@directory, "default.rb"))
51
- # TODO let default handle it, allowing us to have proxy menus
52
- else
53
- puts "Unknown command #{to_run}"
54
- end
55
- to_run = nil
56
- return if one_shot
57
- end
58
- end
59
-
60
- def commands(prefix='')
61
- completions = []
62
- Dir.new(@directory).each do |command|
63
- if command =~ /^[^\.]/ and command =~ /^#{Regexp.escape(prefix)}/ and File.file?(File.join(@directory, command))
64
- completions << File.basename(command, '.rb')
65
- end
66
- end
67
- completions
68
- end
69
-
70
- def display_help
71
- puts <<EOF
72
- Builtin commands:
73
- help:\t\t\t\tDisplays this message
74
- quit:\t\t\t\tQuits this session
75
- ..: \t\t\t\tGoes up a level in the menu (or quits if at the root)
76
-
77
- #{@parent} commands:
78
- EOF
79
-
80
- # TODO display some help for each submenu
81
- commands.each do |cmd|
82
- require File.join(@directory, "#{cmd}")
83
- puts " #{cmd}:\t\t\t\t#{eval(cmd.camelize).new.description}"
84
- end
85
- end
86
- end