redwood 0.0.1 → 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.
- data/README.md +86 -13
- data/Rakefile +10 -0
- data/bin/redwood +120 -0
- data/lib/redwood.rb +60 -34
- data/lib/redwood/filenode.rb +46 -0
- data/lib/redwood/node.rb +12 -0
- data/man/redwood.1 +86 -0
- data/man/redwood.1.html +128 -0
- data/man/redwood.1.ronn +64 -0
- data/redwood.gemspec +62 -0
- data/test/test_redwood.rb +74 -7
- metadata +12 -6
data/README.md
CHANGED
@@ -1,17 +1,90 @@
|
|
1
|
-
|
1
|
+
# redwood
|
2
2
|
|
3
|
-
|
3
|
+
Simple Ruby trees. Redwood is a simple implementation of a tree data structure in pure Ruby. It provides a few things:
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
* Add tests for it. This is important so I don't break it in a
|
10
|
-
future version unintentionally.
|
11
|
-
* Commit, do not mess with rakefile, version, or history.
|
12
|
-
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
13
|
-
* Send me a pull request. Bonus points for topic branches.
|
5
|
+
+ The `redwood` command-line tool: like the Unix [`tree`](http://mama.indstate.edu/users/ice/tree/) tool, but in Ruby!
|
6
|
+
+ The Redwood module for basic tree-esqueness.
|
7
|
+
+ Redwood::Node class for basic tree-nodiness
|
8
|
+
+ Redwood::FileNode class for representing Directories and Files in a tree-like way.
|
14
9
|
|
15
|
-
|
10
|
+
[RDoc](http://rdoc.info/projects/mwunsch/redwood) | [Gem](http://rubygems.org/gems/redwood)
|
16
11
|
|
17
|
-
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
gem install redwood
|
15
|
+
|
16
|
+
## `redwood`
|
17
|
+
|
18
|
+
The `redwood` command-line tool attempts a pure Ruby implementation of [tree](http://man.cx/tree).
|
19
|
+
|
20
|
+
USAGE: redwood [ OPTIONS ] [ DIRECTORY ]
|
21
|
+
|
22
|
+
Looks a bit like this:
|
23
|
+
|
24
|
+
Redwood
|
25
|
+
|-- bin
|
26
|
+
| `-- redwood
|
27
|
+
|-- Gemfile
|
28
|
+
|-- lib
|
29
|
+
| |-- redwood
|
30
|
+
| | |-- filenode.rb
|
31
|
+
| | `-- node.rb
|
32
|
+
| `-- redwood.rb
|
33
|
+
|-- LICENSE
|
34
|
+
|-- pkg
|
35
|
+
| `-- redwood-0.0.1.gem
|
36
|
+
|-- Rakefile
|
37
|
+
|-- README.md
|
38
|
+
|-- redwood.gemspec
|
39
|
+
`-- test
|
40
|
+
|-- helper.rb
|
41
|
+
`-- test_redwood.rb
|
42
|
+
|
43
|
+
5 directories, 12 files
|
44
|
+
|
45
|
+
Help is a `redwood --help` away. See also: [redwood(1)](http://mwunsch.github.com/redwood/)
|
46
|
+
|
47
|
+
## `Redwood`
|
48
|
+
|
49
|
+
The Redwood module is a module for including/extending tree-like features on your objects. It stores nodes in an Array. The only requirement for children is that they too include/extend tree-like features.
|
50
|
+
|
51
|
+
Methods include:
|
52
|
+
|
53
|
+
root? ## Is this a root node? Meaning, it has no parent.
|
54
|
+
leaf? ## Is this a leaf node? Meaning, is it without children?
|
55
|
+
root ## Get the root node in this tree.
|
56
|
+
children ## Get the children of this node.
|
57
|
+
siblings ## Get this nodes siblings.
|
58
|
+
only_child? ## Is this node without siblings?
|
59
|
+
has_children? ## Does this node have children?
|
60
|
+
ancestors ## All of the parent nodes of this node.
|
61
|
+
descendants ## All of the descendant nodes of this node.
|
62
|
+
depth ## Integer representing how deep this node is in the tree.
|
63
|
+
## A root node has a depth of 1, its children: 2, etc.
|
64
|
+
unlink ## Detach this node from its parent.
|
65
|
+
prune ## Unlink all of this node's chidren.
|
66
|
+
walk ## Recursively yield every node in this tree to a block
|
67
|
+
view ## Make a fancy string representation of the tree
|
68
|
+
## as seen in the command-line tool
|
69
|
+
|
70
|
+
### Redwood::Node
|
71
|
+
|
72
|
+
The Redwood::Node class is a simple implementation of the Redwood module. It is a good starting point for other trees. It adds new methods:
|
73
|
+
|
74
|
+
add_child(name) ## Add a child node. Nodes can have a #name.
|
75
|
+
[](name) ## Lookup children node by their #name.
|
76
|
+
<<(node) ## Add a node to this node's children.
|
77
|
+
|
78
|
+
#### Redwood::FileNode
|
79
|
+
|
80
|
+
The Redwood::FileNode class is an example use-case for Redwood, and it powers the `redwood` CLI. It stores a directory tree in a Redwood-backed structure. It has one primary method that does the magic:
|
81
|
+
|
82
|
+
dir = Redwood::FileNode.scandir '~/Projects/Redwood'
|
83
|
+
|
84
|
+
That will go through the directory and build a Redwood tree. Redwood::FileNode objects have methods that correspond to the `File` class. So you can do things like `dir.directory?` or `dir.chmod`.
|
85
|
+
|
86
|
+
Now go forth and grow some Ruby-flavored trees.
|
87
|
+
|
88
|
+
## Copyright
|
89
|
+
|
90
|
+
Redwood is Copyright (c) 2010 Mark Wunsch and is licensed under the [MIT License](http://creativecommons.org/licenses/MIT/).
|
data/Rakefile
CHANGED
@@ -46,3 +46,13 @@ desc "Open an irb session preloaded with this library"
|
|
46
46
|
task :console do
|
47
47
|
sh "irb -rubygems -I lib -r redwood"
|
48
48
|
end
|
49
|
+
|
50
|
+
desc "Build the manual"
|
51
|
+
task :build_man do
|
52
|
+
sh "ronn -br5 --organization='Mark Wunsch' --manual='Redwood Manual' man/*.ronn"
|
53
|
+
end
|
54
|
+
|
55
|
+
desc "Show the manual"
|
56
|
+
task :man => :build_man do
|
57
|
+
exec "man man/redwood.1"
|
58
|
+
end
|
data/bin/redwood
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
## Redwood is an implementation of `tree` in Ruby
|
3
|
+
##
|
4
|
+
## Usage: redwood [ OPTIONS ] [ DIRECTORY ]
|
5
|
+
##
|
6
|
+
## Learn more about the original at:
|
7
|
+
## http://mama.indstate.edu/users/ice/tree/
|
8
|
+
##
|
9
|
+
##
|
10
|
+
|
11
|
+
require 'optparse'
|
12
|
+
|
13
|
+
def usage
|
14
|
+
File.readlines(__FILE__).
|
15
|
+
grep(/^##.*/).
|
16
|
+
map { |line| line.chomp[3..-1] }.
|
17
|
+
join("\n")
|
18
|
+
end
|
19
|
+
|
20
|
+
begin
|
21
|
+
require 'redwood'
|
22
|
+
rescue LoadError
|
23
|
+
raise if $!.to_s !~ /redwood/
|
24
|
+
libdir = File.expand_path("../../lib", __FILE__).sub(/^#{Dir.pwd}/, '.')
|
25
|
+
if !$:.include?(libdir)
|
26
|
+
$:.unshift libdir
|
27
|
+
retry
|
28
|
+
end
|
29
|
+
raise
|
30
|
+
end
|
31
|
+
|
32
|
+
options = {
|
33
|
+
:follow_symlinks => false,
|
34
|
+
:show_hidden_files => false
|
35
|
+
}
|
36
|
+
ARGV.options do |option|
|
37
|
+
option.banner = usage
|
38
|
+
option.separator "Options"
|
39
|
+
option.on('-a','All files are listed.') { options[:show_hidden_files] = true }
|
40
|
+
option.on('-d','List directories only.') { options[:only_directories] = true }
|
41
|
+
option.on('-l','Follow symbolic links like directories.') { options[:follow_symlinks] = true }
|
42
|
+
option.on('-f','Print the full path prefix for each file.') { options[:full_path] = true }
|
43
|
+
option.on('-s','Print the size in bytes of each file.') { options[:size] = true }
|
44
|
+
option.on('-D','Print the date of last modification.') { options[:date] = :mtime }
|
45
|
+
option.on('-F',"Appends '/', '@', '=', '*', or '|' as per ls -F.") { options[:ftype] = true }
|
46
|
+
option.on('-L level','Descend only level directories deep.') { |depth| options[:depth] = depth.to_i + 1}
|
47
|
+
option.separator ""
|
48
|
+
option.on_tail('--version','Prints version and exits.') { puts Redwood::VERSION ; exit }
|
49
|
+
option.on_tail('--help','Prints this help screen.') { puts option ; exit }
|
50
|
+
option.parse!
|
51
|
+
end
|
52
|
+
|
53
|
+
def statement(tree)
|
54
|
+
directories = 0
|
55
|
+
files = 0
|
56
|
+
tree.descendants.each do |f|
|
57
|
+
if f.directory?
|
58
|
+
directories += 1
|
59
|
+
else
|
60
|
+
files += 1
|
61
|
+
end
|
62
|
+
end
|
63
|
+
d = directories.eql?(1) ? 'directory' : 'directories'
|
64
|
+
f = files.eql?(1) ? 'file' : 'files'
|
65
|
+
"#{directories} #{d}, #{files} #{f}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def setup_tree(tree, options)
|
69
|
+
if options[:depth]
|
70
|
+
abort 'Invalid level, must be greater than 0' if options[:depth] <= 1
|
71
|
+
tree.descendants.each {|f| f.unlink if f.depth > options[:depth] }
|
72
|
+
end
|
73
|
+
if !options[:follow_symlinks]
|
74
|
+
tree.descendants.each do |f|
|
75
|
+
if f.symlink?
|
76
|
+
f.value << " -> #{f.readlink}"
|
77
|
+
end
|
78
|
+
f.unlink if f.parent.symlink?
|
79
|
+
end
|
80
|
+
end
|
81
|
+
if options[:only_directories]
|
82
|
+
tree.descendants.each {|f| f.unlink if !f.directory? }
|
83
|
+
end
|
84
|
+
if !options[:show_hidden_files]
|
85
|
+
tree.descendants.each do |f|
|
86
|
+
f.unlink if f.basename.index('.').eql?(0)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
tree.walk {|f| f.value = f.path } if options[:full_path]
|
90
|
+
|
91
|
+
if options[:date]
|
92
|
+
tree.descendants.each {|f| f.value.insert(0,"[#{f.send(options[:date]).strftime('%b %d %H:%M')}] ") }
|
93
|
+
end
|
94
|
+
if options[:size]
|
95
|
+
tree.descendants.each {|f| f.value.insert(0,"[#{f.size}] ") if f.size? }
|
96
|
+
end
|
97
|
+
if options[:ftype]
|
98
|
+
tree.descendants.each do |f|
|
99
|
+
f.value << "|" if f.ftype == 'fifo'
|
100
|
+
if f.symlink?
|
101
|
+
f.value << "@"
|
102
|
+
elsif f.directory?
|
103
|
+
f.value << "/"
|
104
|
+
end
|
105
|
+
f.value << "*" if f.executable? && f.file?
|
106
|
+
f.value << "=" if f.socket?
|
107
|
+
end
|
108
|
+
end
|
109
|
+
tree
|
110
|
+
end
|
111
|
+
|
112
|
+
dir = ARGV.empty? ? '.' : ARGV.first
|
113
|
+
abort %Q{"#{dir}" is not a directory.} if !File.directory?(dir)
|
114
|
+
|
115
|
+
tree = setup_tree Redwood::FileNode.scandir(dir), options
|
116
|
+
puts tree.view(:value)
|
117
|
+
puts "\n"
|
118
|
+
puts statement(tree)
|
119
|
+
exit
|
120
|
+
|
data/lib/redwood.rb
CHANGED
@@ -1,29 +1,27 @@
|
|
1
|
-
# The
|
1
|
+
# The Redwood module can be mixed in to give tree-like methods to an object.
|
2
2
|
# Its primary implementation is the Redwood::Node class. Its only requirement
|
3
3
|
# is that the tree-infused-object's children and parent is an object that
|
4
|
-
# also mixes in
|
4
|
+
# also mixes in tree-like methods. See Redwood::Node for the canononical representation.
|
5
5
|
|
6
6
|
module Redwood
|
7
|
-
VERSION = "0.0
|
7
|
+
VERSION = "0.1.0"
|
8
8
|
|
9
|
+
# This node's parent.
|
9
10
|
def parent
|
10
11
|
@parent
|
11
12
|
end
|
12
13
|
|
13
|
-
|
14
|
-
end
|
15
|
-
|
16
|
-
def value
|
17
|
-
end
|
18
|
-
|
14
|
+
# Is this node the root of the tree?
|
19
15
|
def root?
|
20
16
|
parent.nil?
|
21
17
|
end
|
22
18
|
|
19
|
+
# Is this node a leaf node? Is this node childless?
|
23
20
|
def leaf?
|
24
|
-
children.empty?
|
21
|
+
children.nil? || children.empty?
|
25
22
|
end
|
26
23
|
|
24
|
+
# Get the root node in this tree.
|
27
25
|
def root
|
28
26
|
if root?
|
29
27
|
self
|
@@ -31,56 +29,84 @@ module Redwood
|
|
31
29
|
parent.root
|
32
30
|
end
|
33
31
|
end
|
34
|
-
|
32
|
+
|
33
|
+
# Get the children of this node.
|
35
34
|
def children
|
36
35
|
@children ||= []
|
37
36
|
end
|
38
37
|
|
38
|
+
# Get the siblings of this node. The other children belonging to this node's parent.
|
39
39
|
def siblings
|
40
40
|
if parent
|
41
41
|
parent.children.reject {|child| child == self }
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
+
# Is this node the only child of its parent. Does it have any siblings?
|
45
46
|
def only_child?
|
46
47
|
if parent
|
47
48
|
siblings.empty?
|
48
49
|
end
|
49
50
|
end
|
50
51
|
|
51
|
-
|
52
|
-
children.nil? || children.empty?
|
53
|
-
end
|
54
|
-
|
52
|
+
# Does this node have children? Is it not a leaf node?
|
55
53
|
def has_children?
|
56
|
-
!
|
54
|
+
!leaf?
|
57
55
|
end
|
58
|
-
|
56
|
+
|
57
|
+
# Get all of the ancestors for this node.
|
59
58
|
def ancestors
|
60
|
-
|
61
|
-
@ancestors = []
|
59
|
+
ancestors = []
|
62
60
|
if parent
|
63
|
-
|
64
|
-
parent.ancestors.each {|ancestor|
|
61
|
+
ancestors << parent
|
62
|
+
parent.ancestors.each {|ancestor| ancestors << ancestor }
|
65
63
|
end
|
66
|
-
|
64
|
+
ancestors
|
67
65
|
end
|
68
|
-
|
66
|
+
|
67
|
+
# Get all of the descendants of this node.
|
68
|
+
# All of its children, and its childrens' children, and its childrens' childrens' children...
|
69
69
|
def descendants
|
70
|
-
|
71
|
-
@descendants = []
|
70
|
+
descendants = []
|
72
71
|
if !children.empty?
|
73
|
-
(
|
74
|
-
children.each {|descendant|
|
75
|
-
|
72
|
+
(descendants << children).flatten!
|
73
|
+
children.each {|descendant| descendants << descendant.descendants }
|
74
|
+
descendants.flatten!
|
76
75
|
end
|
77
|
-
|
76
|
+
descendants
|
78
77
|
end
|
79
|
-
|
78
|
+
|
79
|
+
# An integer representation of how deep in the tree this node is.
|
80
|
+
# The root node has a depth of 1, its children have a depth of 2, etc.
|
80
81
|
def depth
|
81
82
|
ancestors.size + 1
|
82
83
|
end
|
83
84
|
|
85
|
+
# Orphan this node. Remove it from its parent node.
|
86
|
+
def unlink
|
87
|
+
if parent
|
88
|
+
parent.children.delete(self)
|
89
|
+
self.instance_variable_set(:@parent, nil)
|
90
|
+
return self
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Abandon all of this node's children.
|
95
|
+
def prune
|
96
|
+
if children
|
97
|
+
children.each {|child| child.unlink }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Recursively yield every node in the tree.
|
102
|
+
def walk(&block)
|
103
|
+
if block_given?
|
104
|
+
yield self
|
105
|
+
children.each {|child| child.walk(&block) }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Makes a pretty string representation of the tree.
|
84
110
|
def view(content = :name)
|
85
111
|
treeview = ''
|
86
112
|
if parent
|
@@ -88,7 +114,7 @@ module Redwood
|
|
88
114
|
treeview << "--\s"
|
89
115
|
end
|
90
116
|
treeview << "#{self.send(content)}"
|
91
|
-
if
|
117
|
+
if has_children?
|
92
118
|
treeview << "\n"
|
93
119
|
children.each do |child|
|
94
120
|
if parent
|
@@ -109,6 +135,6 @@ module Redwood
|
|
109
135
|
treeview
|
110
136
|
end
|
111
137
|
|
112
|
-
|
113
|
-
|
114
|
-
|
138
|
+
autoload :FileNode, 'redwood/filenode'
|
139
|
+
autoload :Node, 'redwood/node'
|
140
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# Redwood::FileNode stores a Directory tree in a Redwood structure.
|
2
|
+
# FileNodes respond to methods of the File class.
|
3
|
+
# eg. FileNode#chmod, FileNode#stat, etc.
|
4
|
+
|
5
|
+
module Redwood
|
6
|
+
class FileNode < Node
|
7
|
+
|
8
|
+
# Takes a path and scans the directory, creating a Redwood tree.
|
9
|
+
def self.scandir(dir = Dir.pwd, tree=nil)
|
10
|
+
node = tree ? tree : self.new(dir)
|
11
|
+
if File.directory?(dir)
|
12
|
+
Dir.foreach(dir) do |d|
|
13
|
+
if File.directory?("#{dir}/#{d}")
|
14
|
+
node << scandir("#{dir}/#{d}",tree) unless (d.eql?('..') || d.eql?('.'))
|
15
|
+
else
|
16
|
+
node.add_child("#{dir}/#{d}")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
else
|
20
|
+
node.add_child(dir)
|
21
|
+
end
|
22
|
+
node
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :path
|
26
|
+
|
27
|
+
def initialize(name, parent=nil)
|
28
|
+
super
|
29
|
+
@path = File.expand_path(name)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Some information to store in the node. Defaults to the basename of the file/directory
|
33
|
+
def value
|
34
|
+
@value ||= basename
|
35
|
+
end
|
36
|
+
|
37
|
+
def method_missing(method, *args, &block)
|
38
|
+
if File.respond_to?(method)
|
39
|
+
File.send method, path
|
40
|
+
else
|
41
|
+
super
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
data/lib/redwood/node.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
+
# A basic representation of a Redwood tree.
|
2
|
+
|
1
3
|
module Redwood
|
2
4
|
class Node
|
3
5
|
include Redwood
|
4
6
|
|
5
7
|
attr_reader :name
|
8
|
+
attr_accessor :value
|
6
9
|
|
7
10
|
def initialize(name=nil, parent=nil)
|
8
11
|
@name = name
|
@@ -12,10 +15,19 @@ module Redwood
|
|
12
15
|
# Creates a child, adds it to children, and returns the child
|
13
16
|
def add_child(name)
|
14
17
|
child = self.class.new(name, self)
|
18
|
+
yield child if block_given?
|
15
19
|
children << child
|
16
20
|
child
|
17
21
|
end
|
18
22
|
|
23
|
+
# Add a node to this nodes children, and return the child
|
24
|
+
def <<(child)
|
25
|
+
child.instance_variable_set(:@parent, self)
|
26
|
+
children << child
|
27
|
+
child
|
28
|
+
end
|
29
|
+
|
30
|
+
# Lookup a child node by its name
|
19
31
|
def [](key)
|
20
32
|
selected_child = children.select {|child| child.name == key }
|
21
33
|
selected_child.size.eql?(1) ? selected_child.first : selected_child
|
data/man/redwood.1
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
.\" generated with Ronn/v0.5
|
2
|
+
.\" http://github.com/rtomayko/ronn/
|
3
|
+
.
|
4
|
+
.TH "REDWOOD" "1" "April 2010" "Mark Wunsch" "Redwood Manual"
|
5
|
+
.
|
6
|
+
.SH "NAME"
|
7
|
+
\fBredwood\fR \-\- Ruby\-flavored tree
|
8
|
+
.
|
9
|
+
.SH "SYNOPSIS"
|
10
|
+
\fBredwood\fR [\fIOPTIONS\fR] \fIDIRECTORY\fR
|
11
|
+
.
|
12
|
+
.SH "DESCRIPTION"
|
13
|
+
\fBredwood\fR is an implementation of \fBtree\fR in Ruby. Like the original \fBTree\fR, \fBRedwood\fR is a recursive directory listing program, producing a pretty\-looking depth indented listing of directory contents. Without arguments, \fBredwood\fR lists the files in the current directory. Like \fBtree\fR, after listing, \fBredwood\fR prints a summary of the total number of files and/or directories listed.
|
14
|
+
.
|
15
|
+
.P
|
16
|
+
And, again like the original \fBtree\fR, symbolic links are not followed and hidden files (those beginning with a '.') remain unseen by default. You can reveal them with options. File system constructs, the current directory as '.' and the parent directory as '..', are never printed.
|
17
|
+
.
|
18
|
+
.P
|
19
|
+
Learn more about the original \fBtree\fR with tree(1) and at http://mama.indstate.edu/users/ice/tree/
|
20
|
+
.
|
21
|
+
.P
|
22
|
+
This is a proof\-of\-concept. It's written in Ruby. It does half of what \fBtree\fR does pretty well. You should probably just use \fBtree\fR.
|
23
|
+
.
|
24
|
+
.SH "OPTIONS"
|
25
|
+
.
|
26
|
+
.TP
|
27
|
+
\fB\-a\fR
|
28
|
+
Print all files, even hidden ones (that begin with a '.').
|
29
|
+
.
|
30
|
+
.TP
|
31
|
+
\fB\-d\fR
|
32
|
+
Only list directories.
|
33
|
+
.
|
34
|
+
.TP
|
35
|
+
\fB\-l\fR
|
36
|
+
Follow symbolic links (that point to directories), as though they were directories. There is no protection from recursion, so don't do that.
|
37
|
+
.
|
38
|
+
.TP
|
39
|
+
\fB\-f\fR
|
40
|
+
Print the full path prefix for each file.
|
41
|
+
.
|
42
|
+
.TP
|
43
|
+
\fB\-s\fR
|
44
|
+
Print the size of each file in bytes.
|
45
|
+
.
|
46
|
+
.TP
|
47
|
+
\fB\-D\fR
|
48
|
+
Print the date of last modification for the file, in the format like: 'Aug 25 14:92'
|
49
|
+
.
|
50
|
+
.TP
|
51
|
+
\fB\-F\fR
|
52
|
+
Appends '/' to directories, '@' to symlinks, '=' to sockets, '*' to executables, and '|' to FIFO's, as per ls \-F.
|
53
|
+
.
|
54
|
+
.TP
|
55
|
+
\fB\-L\fR \fIlevel\fR
|
56
|
+
Max display depth of the directory tree. Has got to be greater than 0.
|
57
|
+
.
|
58
|
+
.P
|
59
|
+
Other:
|
60
|
+
.
|
61
|
+
.TP
|
62
|
+
\fB\-\-help\fR
|
63
|
+
Print the help message and quit.
|
64
|
+
.
|
65
|
+
.TP
|
66
|
+
\fB\-\-version\fR
|
67
|
+
Print the \fBredwood\fR version and quit.
|
68
|
+
.
|
69
|
+
.SH "INSTALLATION"
|
70
|
+
If you have RubyGems installed:
|
71
|
+
.
|
72
|
+
.IP "" 4
|
73
|
+
.
|
74
|
+
.nf
|
75
|
+
|
76
|
+
gem install redwood
|
77
|
+
.
|
78
|
+
.fi
|
79
|
+
.
|
80
|
+
.IP "" 0
|
81
|
+
.
|
82
|
+
.SH "COPYRIGHT"
|
83
|
+
Redwood is Copyright (C) 2010 Mark Wunsch
|
84
|
+
.
|
85
|
+
.SH "SEE ALSO"
|
86
|
+
tree(1), ls(1)
|
data/man/redwood.1.html
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta http-equiv='content-type' value='text/html;charset=utf8'>
|
5
|
+
<meta name='generator' value='Ronn/v0.5'>
|
6
|
+
<title>redwood(1) -- Ruby-flavored tree</title>
|
7
|
+
<style type='text/css'>
|
8
|
+
body {margin:0}
|
9
|
+
#man, #man code, #man pre, #man tt, #man kbd, #man samp {
|
10
|
+
font-family:consolas,monospace;
|
11
|
+
font-size:16px;
|
12
|
+
line-height:1.3;
|
13
|
+
color:#343331;
|
14
|
+
background:#fff; }
|
15
|
+
#man { max-width:89ex; text-align:justify; margin:0 25px 25px 25px }
|
16
|
+
#man h1, #man h2, #man h3 { color:#232221;clear:left }
|
17
|
+
#man h1 { font-size:28px; margin:15px 0 30px 0; text-align:center }
|
18
|
+
#man h2 { font-size:18px; margin-bottom:0; margin-top:10px; line-height:1.3; }
|
19
|
+
#man h3 { font-size:16px; margin:0 0 0 4ex; }
|
20
|
+
#man p, #man ul, #man ol, #man dl, #man pre { margin:0 0 18px 0; }
|
21
|
+
#man pre {
|
22
|
+
color:#333231;
|
23
|
+
background:#edeceb;
|
24
|
+
padding:5px 7px;
|
25
|
+
margin:0px 0 20px 0;
|
26
|
+
border-left:2ex solid #ddd}
|
27
|
+
#man pre + h2, #man pre + h3 {
|
28
|
+
margin-top:22px;
|
29
|
+
}
|
30
|
+
#man h2 + pre, #man h3 + pre {
|
31
|
+
margin-top:5px;
|
32
|
+
}
|
33
|
+
#man > p, #man > ul, #man > ol, #man > dl, #man > pre { margin-left:8ex; }
|
34
|
+
#man dt { margin:0; clear:left }
|
35
|
+
#man dt.flush { float:left; width:8ex }
|
36
|
+
#man dd { margin:0 0 0 9ex }
|
37
|
+
#man code, #man strong, #man b { font-weight:bold; color:#131211; }
|
38
|
+
#man pre code { font-weight:normal; color:#232221; background:inherit }
|
39
|
+
#man em, var, u {
|
40
|
+
font-style:normal; color:#333231; border-bottom:1px solid #999; }
|
41
|
+
#man h1.man-title { display:none; }
|
42
|
+
#man ol.man, #man ol.man li { margin:2px 0 10px 0; padding:0;
|
43
|
+
float:left; width:33%; list-style-type:none;
|
44
|
+
text-transform:uppercase; font-size:18px; color:#999;
|
45
|
+
letter-spacing:1px;}
|
46
|
+
#man ol.man { width:100%; }
|
47
|
+
#man ol.man li.tl { text-align:left }
|
48
|
+
#man ol.man li.tc { text-align:center;letter-spacing:4px }
|
49
|
+
#man ol.man li.tr { text-align:right }
|
50
|
+
#man ol.man a { color:#999 }
|
51
|
+
#man ol.man a:hover { color:#333231 }
|
52
|
+
</style>
|
53
|
+
</head>
|
54
|
+
<body>
|
55
|
+
<div id='man'>
|
56
|
+
|
57
|
+
<h1 class='man-title'>redwood(1)</h1>
|
58
|
+
|
59
|
+
<ol class='head man'>
|
60
|
+
<li class='tl'>redwood(1)</li>
|
61
|
+
<li class='tc'>Redwood Manual</li>
|
62
|
+
<li class='tr'>redwood(1)</li>
|
63
|
+
</ol>
|
64
|
+
|
65
|
+
<h2 id='NAME'>NAME</h2>
|
66
|
+
<p><code>redwood</code> -- Ruby-flavored tree</p>
|
67
|
+
|
68
|
+
<h2>SYNOPSIS</h2>
|
69
|
+
|
70
|
+
<p><code>redwood</code> [<var>OPTIONS</var>] <var>DIRECTORY</var></p>
|
71
|
+
|
72
|
+
<h2>DESCRIPTION</h2>
|
73
|
+
|
74
|
+
<p><code>redwood</code> is an implementation of <code>tree</code> in Ruby. Like the original <code>Tree</code>, <code>Redwood</code> is a recursive directory listing program, producing a pretty-looking depth indented listing of directory contents. Without arguments, <code>redwood</code> lists the files in the current directory. Like <code>tree</code>, after listing, <code>redwood</code> prints a summary of the total number of files and/or directories listed.</p>
|
75
|
+
|
76
|
+
<p>And, again like the original <code>tree</code>, symbolic links are not followed and hidden files (those beginning with a '.') remain unseen by default. You can reveal them with options. File system constructs, the current directory as '.' and the parent directory as '..', are never printed.</p>
|
77
|
+
|
78
|
+
<p>Learn more about the original <code>tree</code> with tree(1) and at http://mama.indstate.edu/users/ice/tree/</p>
|
79
|
+
|
80
|
+
<p>This is a proof-of-concept. It's written in Ruby. It does half of what <code>tree</code> does pretty well. You should probably just use <code>tree</code>.</p>
|
81
|
+
|
82
|
+
<h2>OPTIONS</h2>
|
83
|
+
|
84
|
+
<dl>
|
85
|
+
<dt class="flush"><code>-a</code></dt><dd><p> Print all files, even hidden ones (that begin with a '.').</p></dd>
|
86
|
+
<dt class="flush"><code>-d</code></dt><dd><p> Only list directories.</p></dd>
|
87
|
+
<dt class="flush"><code>-l</code></dt><dd><p> Follow symbolic links (that point to directories), as though they were directories. There is no protection from recursion, so don't do that.</p></dd>
|
88
|
+
<dt class="flush"><code>-f</code></dt><dd><p> Print the full path prefix for each file.</p></dd>
|
89
|
+
<dt class="flush"><code>-s</code></dt><dd><p> Print the size of each file in bytes.</p></dd>
|
90
|
+
<dt class="flush"><code>-D</code></dt><dd><p> Print the date of last modification for the file, in the format like: 'Aug 25 14:92'</p></dd>
|
91
|
+
<dt class="flush"><code>-F</code></dt><dd><p> Appends '/' to directories, '@' to symlinks, '=' to sockets, '*' to executables, and '|' to FIFO's, as per ls -F.</p></dd>
|
92
|
+
<dt><code>-L</code> <em>level</em></dt><dd><p> Max display depth of the directory tree. Has got to be greater than 0.</p></dd>
|
93
|
+
</dl>
|
94
|
+
|
95
|
+
|
96
|
+
<p>Other:</p>
|
97
|
+
|
98
|
+
<dl>
|
99
|
+
<dt class="flush"><code>--help</code></dt><dd><p> Print the help message and quit.</p></dd>
|
100
|
+
<dt><code>--version</code></dt><dd><p> Print the <code>redwood</code> version and quit.</p></dd>
|
101
|
+
</dl>
|
102
|
+
|
103
|
+
|
104
|
+
<h2>INSTALLATION</h2>
|
105
|
+
|
106
|
+
<p>If you have RubyGems installed:</p>
|
107
|
+
|
108
|
+
<pre><code>gem install redwood
|
109
|
+
</code></pre>
|
110
|
+
|
111
|
+
<h2>COPYRIGHT</h2>
|
112
|
+
|
113
|
+
<p>Redwood is Copyright (C) 2010 Mark Wunsch</p>
|
114
|
+
|
115
|
+
<h2>SEE ALSO</h2>
|
116
|
+
|
117
|
+
<p>tree(1), ls(1)</p>
|
118
|
+
|
119
|
+
|
120
|
+
<ol class='foot man'>
|
121
|
+
<li class='tl'>Mark Wunsch</li>
|
122
|
+
<li class='tc'>April 2010</li>
|
123
|
+
<li class='tr'>redwood(1)</li>
|
124
|
+
</ol>
|
125
|
+
|
126
|
+
</div>
|
127
|
+
</body>
|
128
|
+
</html>
|
data/man/redwood.1.ronn
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
redwood(1) -- Ruby-flavored tree
|
2
|
+
===================================
|
3
|
+
|
4
|
+
## SYNOPSIS
|
5
|
+
|
6
|
+
`redwood` [<OPTIONS>] <DIRECTORY>
|
7
|
+
|
8
|
+
## DESCRIPTION
|
9
|
+
|
10
|
+
`redwood` is an implementation of `tree` in Ruby. Like the original `Tree`, `Redwood` is a recursive directory listing program, producing a pretty-looking depth indented listing of directory contents. Without arguments, `redwood` lists the files in the current directory. Like `tree`, after listing, `redwood` prints a summary of the total number of files and/or directories listed.
|
11
|
+
|
12
|
+
And, again like the original `tree`, symbolic links are not followed and hidden files (those beginning with a '.') remain unseen by default. You can reveal them with options. File system constructs, the current directory as '.' and the parent directory as '..', are never printed.
|
13
|
+
|
14
|
+
Learn more about the original `tree` with tree(1) and at http://mama.indstate.edu/users/ice/tree/
|
15
|
+
|
16
|
+
This is a proof-of-concept. It's written in Ruby. It does half of what `tree` does pretty well. You should probably just use `tree`.
|
17
|
+
|
18
|
+
## OPTIONS
|
19
|
+
|
20
|
+
* `-a`:
|
21
|
+
Print all files, even hidden ones (that begin with a '.').
|
22
|
+
|
23
|
+
* `-d`:
|
24
|
+
Only list directories.
|
25
|
+
|
26
|
+
* `-l`:
|
27
|
+
Follow symbolic links (that point to directories), as though they were directories. There is no protection from recursion, so don't do that.
|
28
|
+
|
29
|
+
* `-f`:
|
30
|
+
Print the full path prefix for each file.
|
31
|
+
|
32
|
+
* `-s`:
|
33
|
+
Print the size of each file in bytes.
|
34
|
+
|
35
|
+
* `-D`:
|
36
|
+
Print the date of last modification for the file, in the format like: 'Aug 25 14:92'
|
37
|
+
|
38
|
+
* `-F`:
|
39
|
+
Appends '/' to directories, '@' to symlinks, '=' to sockets, '*' to executables, and '|' to FIFO's, as per ls -F.
|
40
|
+
|
41
|
+
* `-L` _level_:
|
42
|
+
Max display depth of the directory tree. Has got to be greater than 0.
|
43
|
+
|
44
|
+
Other:
|
45
|
+
|
46
|
+
* `--help`:
|
47
|
+
Print the help message and quit.
|
48
|
+
|
49
|
+
* `--version`:
|
50
|
+
Print the `redwood` version and quit.
|
51
|
+
|
52
|
+
## INSTALLATION
|
53
|
+
|
54
|
+
If you have RubyGems installed:
|
55
|
+
|
56
|
+
gem install redwood
|
57
|
+
|
58
|
+
## COPYRIGHT
|
59
|
+
|
60
|
+
Redwood is Copyright (C) 2010 Mark Wunsch
|
61
|
+
|
62
|
+
## SEE ALSO
|
63
|
+
|
64
|
+
tree(1), ls(1)
|
data/redwood.gemspec
ADDED
@@ -0,0 +1,62 @@
|
|
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
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{redwood}
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Mark Wunsch"]
|
12
|
+
s.date = %q{2010-04-10}
|
13
|
+
s.default_executable = %q{redwood}
|
14
|
+
s.description = %q{A simple library to create and manage basic tree-esque structures.}
|
15
|
+
s.email = ["mark@markwunsch.com"]
|
16
|
+
s.executables = ["redwood"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE",
|
19
|
+
"README.md"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".document",
|
23
|
+
".gitignore",
|
24
|
+
"Gemfile",
|
25
|
+
"LICENSE",
|
26
|
+
"README.md",
|
27
|
+
"Rakefile",
|
28
|
+
"bin/redwood",
|
29
|
+
"lib/redwood.rb",
|
30
|
+
"lib/redwood/filenode.rb",
|
31
|
+
"lib/redwood/node.rb",
|
32
|
+
"man/redwood.1",
|
33
|
+
"man/redwood.1.html",
|
34
|
+
"man/redwood.1.ronn",
|
35
|
+
"redwood.gemspec",
|
36
|
+
"test/helper.rb",
|
37
|
+
"test/test_redwood.rb"
|
38
|
+
]
|
39
|
+
s.homepage = %q{http://github.com/mwunsch/redwood}
|
40
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
41
|
+
s.require_paths = ["lib"]
|
42
|
+
s.rubygems_version = %q{1.3.6}
|
43
|
+
s.summary = %q{Ruby trees}
|
44
|
+
s.test_files = [
|
45
|
+
"test/helper.rb",
|
46
|
+
"test/test_redwood.rb"
|
47
|
+
]
|
48
|
+
|
49
|
+
if s.respond_to? :specification_version then
|
50
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
51
|
+
s.specification_version = 3
|
52
|
+
|
53
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
54
|
+
s.add_development_dependency(%q<bundler>, [">= 0.9.7"])
|
55
|
+
else
|
56
|
+
s.add_dependency(%q<bundler>, [">= 0.9.7"])
|
57
|
+
end
|
58
|
+
else
|
59
|
+
s.add_dependency(%q<bundler>, [">= 0.9.7"])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
data/test/test_redwood.rb
CHANGED
@@ -7,12 +7,6 @@ class TestRedwood < Test::Unit::TestCase
|
|
7
7
|
assert_equal :test, node.name
|
8
8
|
end
|
9
9
|
|
10
|
-
test 'can be without children' do
|
11
|
-
node = Redwood::Node.new
|
12
|
-
assert node.childless?
|
13
|
-
assert !node.has_children?
|
14
|
-
end
|
15
|
-
|
16
10
|
test 'can be a root element' do
|
17
11
|
node = Redwood::Node.new
|
18
12
|
assert node.root?
|
@@ -126,6 +120,79 @@ class TestRedwood < Test::Unit::TestCase
|
|
126
120
|
assert_respond_to node, :view
|
127
121
|
assert_equal String, node.view.class
|
128
122
|
end
|
129
|
-
|
123
|
+
|
124
|
+
test 'is a leaf node' do
|
125
|
+
node = Redwood::Node.new(:parent)
|
126
|
+
child = node.add_child(:child)
|
127
|
+
|
128
|
+
assert !node.leaf?
|
129
|
+
assert child.leaf?
|
130
|
+
end
|
131
|
+
|
132
|
+
test 'walks the tree' do
|
133
|
+
node = Redwood::Node.new(:parent)
|
134
|
+
dog = node.add_child(:dog)
|
135
|
+
puppy = dog.add_child(:puppy)
|
136
|
+
son = node.add_child(:son)
|
137
|
+
daughter = node.add_child(:daughter)
|
138
|
+
grandson = son.add_child(:grandson)
|
139
|
+
counter = 0
|
140
|
+
node.walk {|n| counter += 1 }
|
141
|
+
assert_equal 6, counter
|
142
|
+
end
|
143
|
+
|
144
|
+
test 'add a child with the << method' do
|
145
|
+
node = Redwood::Node.new(:parent)
|
146
|
+
dog = Redwood::Node.new(:dog)
|
147
|
+
|
148
|
+
node << dog
|
149
|
+
assert_equal node, dog.parent
|
150
|
+
assert node.children.include?(dog)
|
151
|
+
assert !dog.root?
|
152
|
+
assert !node.leaf?
|
153
|
+
end
|
154
|
+
|
155
|
+
test 'has an optional arbitrary value' do
|
156
|
+
node = Redwood::Node.new(:parent)
|
157
|
+
node.value = "hello world"
|
158
|
+
assert_equal "hello world", node.value
|
159
|
+
end
|
160
|
+
|
161
|
+
test 'unlinks a node from its parent' do
|
162
|
+
node = Redwood::Node.new(:parent)
|
163
|
+
dog = node.add_child :dog
|
164
|
+
|
165
|
+
dog.unlink
|
166
|
+
assert node.leaf?
|
167
|
+
assert !node.children.include?(dog)
|
168
|
+
assert dog.root?
|
169
|
+
end
|
170
|
+
|
171
|
+
test 'prunes its children' do
|
172
|
+
node = Redwood::Node.new(:parent)
|
173
|
+
dog = node.add_child :dog
|
174
|
+
|
175
|
+
node.prune
|
176
|
+
assert node.children.empty?
|
177
|
+
assert node.leaf?
|
178
|
+
assert !dog.parent
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
describe 'FileNode' do
|
183
|
+
test 'scan a directory' do
|
184
|
+
dir = Redwood::FileNode.scandir
|
185
|
+
assert_equal Dir.pwd, dir.name
|
186
|
+
end
|
187
|
+
|
188
|
+
test 'implements File methods on the Node' do
|
189
|
+
dir = Redwood::FileNode.scandir
|
190
|
+
assert dir.directory?
|
191
|
+
end
|
192
|
+
|
193
|
+
test 'has a full path' do
|
194
|
+
dir = Redwood::FileNode.scandir('.')
|
195
|
+
assert_equal File.expand_path('.'), dir.path
|
196
|
+
end
|
130
197
|
end
|
131
198
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
- 0
|
8
7
|
- 1
|
9
|
-
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Mark Wunsch
|
@@ -14,8 +14,8 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-04-
|
18
|
-
default_executable:
|
17
|
+
date: 2010-04-10 00:00:00 -04:00
|
18
|
+
default_executable: redwood
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: bundler
|
@@ -34,8 +34,8 @@ dependencies:
|
|
34
34
|
description: A simple library to create and manage basic tree-esque structures.
|
35
35
|
email:
|
36
36
|
- mark@markwunsch.com
|
37
|
-
executables:
|
38
|
-
|
37
|
+
executables:
|
38
|
+
- redwood
|
39
39
|
extensions: []
|
40
40
|
|
41
41
|
extra_rdoc_files:
|
@@ -48,8 +48,14 @@ files:
|
|
48
48
|
- LICENSE
|
49
49
|
- README.md
|
50
50
|
- Rakefile
|
51
|
+
- bin/redwood
|
51
52
|
- lib/redwood.rb
|
53
|
+
- lib/redwood/filenode.rb
|
52
54
|
- lib/redwood/node.rb
|
55
|
+
- man/redwood.1
|
56
|
+
- man/redwood.1.html
|
57
|
+
- man/redwood.1.ronn
|
58
|
+
- redwood.gemspec
|
53
59
|
- test/helper.rb
|
54
60
|
- test/test_redwood.rb
|
55
61
|
has_rdoc: true
|