treerepl 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2011 Jeffrey Palm
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,11 @@
1
+ Provides a way to create command line itnerfaces for web services with
2
+ inherent tree-like structure. There are two examples:
3
+
4
+ - githubrepl
5
+ - rdiorepl
6
+
7
+ They both require some other libraries. The basic idea is this:
8
+
9
+ 1. Define the tree model for your service
10
+ 2. Define the mapping from tree to service
11
+ 3. See the example and go from there
@@ -0,0 +1,30 @@
1
+ $:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
2
+
3
+ # stdlib
4
+ require 'logger'
5
+
6
+ # internal requires
7
+ require 'treerepl/tree'
8
+ require 'treerepl/cmds'
9
+ require 'treerepl/repl'
10
+
11
+ module TreeRepl
12
+ VERSION = '0.0.1'
13
+
14
+
15
+ class << self
16
+ attr_accessor :debug
17
+ attr_accessor :logger
18
+ def log(str)
19
+ logger.debug { str }
20
+ end
21
+ end
22
+ self.debug = false
23
+
24
+ @logger ||= ::Logger.new(STDERR)
25
+
26
+ def self.version
27
+ VERSION
28
+ end
29
+
30
+ end
@@ -0,0 +1,156 @@
1
+ module TreeRepl
2
+
3
+ class Cmd
4
+ attr_reader :repl,:name
5
+ def initialize(repl,name)
6
+ @repl = repl
7
+ @name = name
8
+ end
9
+ def help
10
+ raise 'Implement help()'
11
+ end
12
+ def exec(args)
13
+ raise 'Implement exec(string[])'
14
+ end
15
+ end
16
+
17
+ class Ls < Cmd
18
+ def initialize(repl)
19
+ super(repl,'ls')
20
+ end
21
+ def exec(args)
22
+ def ls_print(n,prefix=nil)
23
+ def pr(s,prefix)
24
+ if prefix
25
+ puts File.join prefix,s
26
+ else
27
+ puts s
28
+ end
29
+ end
30
+ puts if prefix
31
+ ['.','..'].each do |s|
32
+ pr s,prefix
33
+ end
34
+ n.children.each do |node|
35
+ pr node.name,prefix
36
+ end
37
+ end
38
+ args = ['.'] if args.empty?
39
+ args.uniq!
40
+ args.each do |path|
41
+ n = repl.eval_path repl.cur,path
42
+ if n
43
+ prefix = args.length > 1 ? path : nil
44
+ ls_print n,prefix
45
+ end
46
+ end
47
+ end
48
+ def help
49
+ 'List directory'
50
+ end
51
+ end
52
+
53
+ class Cd < Cmd
54
+ def initialize(repl)
55
+ super(repl,'cd')
56
+ end
57
+ def exec(args)
58
+ args = ['/'] if args.empty?
59
+ path = args.join ' '
60
+ n = repl.eval_path repl.cur,path
61
+ repl.cur = n if n
62
+ end
63
+ def help
64
+ 'Change directory'
65
+ end
66
+ end
67
+
68
+ class Pwd < Cmd
69
+ def initialize(repl)
70
+ super(repl,'pwd')
71
+ end
72
+ def exec(args)
73
+ puts cwd
74
+ end
75
+ def help
76
+ 'Print the current working directory'
77
+ end
78
+ end
79
+
80
+ class Help < Cmd
81
+ def initialize(repl)
82
+ super(repl,'help')
83
+ end
84
+ def help
85
+ 'Print this message'
86
+ end
87
+ def exec(args)
88
+ puts 'Commands:'
89
+ repl.commands.sort {|a,b| a.name <=> b.name}.each do |cmd|
90
+ printf " %-10s %s\n",cmd.name,cmd.help
91
+ end
92
+ end
93
+ end
94
+
95
+ class Quit < Cmd
96
+ def initialize(repl)
97
+ super(repl,'quit')
98
+ end
99
+ def help
100
+ 'Quit'
101
+ end
102
+ def exec(args)
103
+ exit 0
104
+ end
105
+ end
106
+
107
+ class Use < Cmd
108
+ def initialize(repl)
109
+ super(repl,'use')
110
+ end
111
+ def help
112
+ 'Start exploring a certain user'
113
+ end
114
+ def exec(args)
115
+ if args.empty?
116
+ STDERR.puts 'Missing required argument'
117
+ return
118
+ end
119
+ username = args[0]
120
+ user = nil
121
+ begin
122
+ user = repl.finder.call username
123
+ rescue Exception => e
124
+ STDERR.puts "Could not create user for name: #{username}"
125
+ STDERR.puts e
126
+ end
127
+ if user
128
+ repl.use repl.root_class.new user
129
+ end
130
+ end
131
+ end
132
+
133
+ class Cat < Cmd
134
+ def initialize(repl)
135
+ super(repl,'cat')
136
+ end
137
+ def help
138
+ 'Shows the contents of whatever it is you selected'
139
+ end
140
+ def exec(args)
141
+ if args.empty?
142
+ STDERR.put 'Required argument'
143
+ return
144
+ end
145
+ args.each do |arg|
146
+ n = repl.eval_path repl.cur,arg
147
+ if n.kind_of? NamedNode
148
+ p n.obj
149
+ else
150
+ STDERR.puts "Uh, not with this node #{n}"
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+ end
@@ -0,0 +1,149 @@
1
+ module TreeRepl
2
+
3
+ class Repl
4
+
5
+ attr_reader :root
6
+ attr_accessor :commands
7
+ attr_accessor :cur
8
+ attr_accessor :root_class
9
+
10
+ # String -> TreeNode
11
+ attr_accessor :finder
12
+
13
+ def initialize(root_class)
14
+ @root_class = root_class
15
+ @finder = nil
16
+ @commands = [Ls,Cd,Pwd,Use,Help,Quit,Cat].map {|cls| cls.new self}
17
+ end
18
+
19
+ def add_command(command_class)
20
+ @commands << command_class.new(self)
21
+ end
22
+
23
+ # ----------------------------------------------------------------------
24
+ # Main
25
+ # ----------------------------------------------------------------------
26
+
27
+ # TreeNode -> Void
28
+ def main(root)
29
+ use root
30
+ strings2cmds = {}
31
+ commands.each do |cmd|
32
+ strings2cmds[cmd.name] = cmd
33
+ end
34
+ def loop(strings2cmds)
35
+ print cwd + '> '
36
+ orig_line = STDIN.readline.strip
37
+ line = orig_line.split(/ /)
38
+ return false if line.empty?
39
+ str = line.shift.downcase
40
+ return true if str == 'quit'
41
+ if not cur
42
+ if str != 'use' and str != 'help'
43
+ STDERR.puts 'You must set a user with \'use\' before anything else.'
44
+ return
45
+ end
46
+ end
47
+ args = line
48
+ cmd = strings2cmds[str]
49
+ if cmd
50
+ begin
51
+ cmd.exec args
52
+ rescue Exception => e
53
+ STDERR.puts 'Trouble executing: ' + orig_line
54
+ raise e
55
+ end
56
+ else
57
+ STDERR.puts 'Unknown command: ' + str
58
+ end
59
+ return false
60
+ end
61
+ while true
62
+ break if loop strings2cmds
63
+ end
64
+ end
65
+
66
+ # ----------------------------------------------------------------------
67
+ # 'Private'
68
+ # ----------------------------------------------------------------------
69
+
70
+ def use(user)
71
+ if user
72
+ @cur = user
73
+ @root = user
74
+ end
75
+ end
76
+
77
+ # TreeNode string -> TreeNode
78
+ def eval_path(node,path)
79
+ path = '.' if not path or path == ''
80
+ if path =~ /^\//
81
+ args = ['/'] + path.gsub(/^\/+/,'').split(/\//)
82
+ else
83
+ args = path.split /\//
84
+ end
85
+ trav = node
86
+ args.each do |arg|
87
+ case arg
88
+ when '.'
89
+ trav = trav
90
+ when '..'
91
+ trav = trav.parent
92
+ when '/'
93
+ trav = root
94
+ else
95
+ found = false
96
+ trav.children.each do |n|
97
+ if n.name == arg
98
+ trav = n
99
+ found = true
100
+ break
101
+ end
102
+ end
103
+ if not found
104
+ STDERR.puts 'Invalid path: ' + path
105
+ return nil
106
+ end
107
+ end
108
+ end
109
+ return trav
110
+ end
111
+
112
+ # void -> string
113
+ def cwd
114
+ path(root,cur).map {|n| n.name}.join('/')
115
+ end
116
+
117
+ # TreeNode string -> TreeNode
118
+ def node_relative_to(node,name)
119
+ if name == '.'
120
+ return node
121
+ elsif name == '..'
122
+ return node.parent
123
+ elsif name == '/'
124
+ return root
125
+ else
126
+ node.children.each do |n|
127
+ if name == n.name
128
+ return n
129
+ end
130
+ end
131
+ end
132
+ return nil
133
+ end
134
+
135
+ # TreeNode TreeNode -> TreeNode[]
136
+ def path(from,dest)
137
+ res = []
138
+ trav = dest
139
+ while trav
140
+ res.push trav
141
+ break if trav == from
142
+ trav = trav.parent
143
+ end
144
+ return res.reverse
145
+ end
146
+
147
+ end
148
+
149
+ end
@@ -0,0 +1,71 @@
1
+ module TreeRepl
2
+
3
+ class TreeNode
4
+
5
+ attr_accessor :name, :parent, :leaf
6
+
7
+ @kids = nil
8
+
9
+ def find_children
10
+ raise 'Implement find_children'
11
+ end
12
+
13
+ def children(force=false)
14
+ if force or not @kids
15
+ @kids = find_children || []
16
+ @kids.each do |node|
17
+ node.parent = self
18
+ end
19
+ end
20
+ @kids
21
+ end
22
+
23
+ end
24
+
25
+ class CmdNode < TreeNode
26
+ attr_reader :cmd
27
+
28
+ class << self
29
+ attr_accessor :classes2tree_nodes
30
+ end
31
+ self.classes2tree_nodes = {}
32
+
33
+ def initialize(obj,cmd,name)
34
+ @obj = obj
35
+ @cmd = cmd
36
+ @name = name || cmd.to_s
37
+ end
38
+ def find_children
39
+ @obj.send(@cmd).map {|v| CmdNode.classes2tree_nodes[v.class].new v}
40
+ end
41
+ end
42
+
43
+ class NamedNode < TreeNode
44
+ attr_reader :obj
45
+ attr_reader :name
46
+ def initialize(obj,name)
47
+ @obj = obj
48
+ @name = name
49
+ end
50
+
51
+ # Creates the children from the provided symbols defined by
52
+ # implementing symbols()
53
+ def find_children
54
+ lst = symbols
55
+ if lst.is_a? Hash
56
+ lst.keys.sort.map {|n| CmdNode.new @obj,lst[n],n}
57
+ else
58
+ lst.sort {|a,b| a.to_s <=> b.to_s}.map {|n| CmdNode.new @obj,n,nil}
59
+ end
60
+ end
61
+
62
+ # -> [symbol] | {string => symbol}
63
+ #
64
+ # The symbols (with possible) mapped names to use for children
65
+ #
66
+ def symbols
67
+ raise 'Implement symbols()'
68
+ end
69
+ end
70
+
71
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: treerepl
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Jeffrey Palm
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-19 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: System for accessing web services for tree-like things via the repl
23
+ email: jeff@jeffpalm.com
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files:
29
+ - README
30
+ - LICENSE
31
+ files:
32
+ - README
33
+ - LICENSE
34
+ - lib/treerepl.rb
35
+ - lib/treerepl/tree.rb
36
+ - lib/treerepl/repl.rb
37
+ - lib/treerepl/cmds.rb
38
+ has_rdoc: true
39
+ homepage: http://github.com/spudtrooper/treerepl
40
+ licenses: []
41
+
42
+ post_install_message:
43
+ rdoc_options:
44
+ - --charset=UTF-8
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ hash: 3
53
+ segments:
54
+ - 0
55
+ version: "0"
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 3
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ requirements: []
66
+
67
+ rubyforge_project: "%NAME"
68
+ rubygems_version: 1.6.1
69
+ signing_key:
70
+ specification_version: 2
71
+ summary: Tree Repl
72
+ test_files: []
73
+