net-ftp-list 2.1.1 → 3.2.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.txt CHANGED
@@ -17,7 +17,6 @@ See the RFC for more guff on LIST and NLST: http://www.ietf.org/rfc/rfc0959.txt
17
17
 
18
18
  == TODO & PROBLEMS
19
19
 
20
- * I'm new to Ruby, I'm sure some exist :)
21
20
  * The factory and abstract base class for parsers are one and the same. OO geeks will cry.
22
21
  * More OS's and server types. Only servers that return Unix like LIST responses will work at the moment.
23
22
  * Calling <tt>if entry.file? or entry.dir?</tt> is hard work when you really mean <tt>unless entry.unknown?</tt>
@@ -34,7 +33,7 @@ See the RFC for more guff on LIST and NLST: http://www.ietf.org/rfc/rfc0959.txt
34
33
  # Ignore everything that's not a file (so symlinks, directories and devices etc.)
35
34
  next unless entry.file?
36
35
 
37
- # If entry isn't a kind_of Net::FTP::List::Unknown then there is a bug in Net::FTP::List if this isn't the
36
+ # If entry isn't entry.unknown? then there is a bug in Net::FTP::List if this isn't the
38
37
  # same name as ftp.nlist('/some/path') would have returned.
39
38
  # Format the entry showing its file size and modification time
40
39
  puts "#{entry.basename}, #{entry.filesize}, #{entry.mtime}"
data/Rakefile CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'rake'
3
+ require 'yaml'
3
4
 
4
5
  begin
5
6
  require 'jeweler'
@@ -17,7 +18,7 @@ end
17
18
  require 'rake/testtask'
18
19
  Rake::TestTask.new(:test) do |test|
19
20
  test.libs << 'lib' << 'test'
20
- test.pattern = 'test/**/*_test.rb'
21
+ test.pattern = 'test/**/test_*.rb'
21
22
  test.verbose = true
22
23
  end
23
24
 
@@ -25,7 +26,7 @@ begin
25
26
  require 'rcov/rcovtask'
26
27
  Rcov::RcovTask.new do |test|
27
28
  test.libs << 'test'
28
- test.pattern = 'test/**/*_test.rb'
29
+ test.pattern = 'test/**/test_*.rb'
29
30
  test.verbose = true
30
31
  end
31
32
  rescue LoadError
@@ -1,5 +1,5 @@
1
1
  ---
2
- :major: 2
3
- :minor: 1
4
- :patch: 1
2
+ :major: 3
3
+ :minor: 2
4
+ :patch: 0
5
5
  :build:
@@ -1,43 +1,35 @@
1
1
  require 'net/ftp'
2
- require 'net/ftp/list/parser'
3
2
 
4
- # The order here is important for the time being. Corse grained parsers should appear before specializations because
5
- # the whole thing is searched in reverse order.
6
- require 'net/ftp/list/unix'
7
- require 'net/ftp/list/microsoft'
8
- require 'net/ftp/list/netware'
3
+ module Net::FTP::List
4
+ require 'net/ftp/list/parser'
5
+ require 'net/ftp/list/entry'
9
6
 
10
- module Net #:nodoc:
11
- class FTP #:nodoc:
7
+ # Parser classes should be listed top to bottom, the most specific
8
+ # (and rare!) server variations coming last
9
+ require 'net/ftp/list/unix'
10
+ require 'net/ftp/list/microsoft'
11
+ require 'net/ftp/list/netware'
12
+ require 'net/ftp/list/rumpus'
13
+ require 'net/ftp/list/unknown'
12
14
 
13
- # Parse FTP LIST responses.
14
- #
15
- # == Creation
16
- #
17
- # require 'net/ftp' # Not really required but I like to list dependencies sometimes.
18
- # require 'net/ftp/list'
19
- #
20
- # ftp = Net::FTP.open('somehost.com', 'user', 'pass')
21
- # ftp.list('/some/path') do |e|
22
- # entry = Net::FTP::List.parse(e)
23
- #
24
- # # Ignore everything that's not a file (so symlinks, directories and devices etc.)
25
- # next unless entry.file?
26
- #
27
- # # If entry isn't a kind_of Net::FTP::List::Unknown then there is a bug in Net::FTP::List if this isn't the
28
- # # same name as ftp.nlist('/some/path') would have returned.
29
- # puts entry.basename
30
- # end
31
- #
32
- # == Exceptions
33
- #
34
- # None at this time. At worst you'll end up with an Net::FTP::List::Unknown instance which won't have any extra
35
- # useful information. Methods like <tt>dir?</tt>, <tt>file?</tt> and <tt>symlink?</tt> will all return +false+.
36
- module List
37
- def self.parse(*args)
38
- Parser.parse(*args)
39
- end
15
+ def self.raise_on_failed_server_detection=(new_flag)
16
+ Thread.current[:net_ftp_list_raise_on_failed_server_detection] = !!new_flag
17
+ end
18
+
19
+ def self.raise_on_failed_server_detection
20
+ Thread.current[:net_ftp_list_raise_on_failed_server_detection]
21
+ end
22
+
23
+ # Parse a line from FTP LIST responsesa and return a Net::FTP::List::Entry
24
+ def self.parse(*args)
25
+ Parser.with_each_parser do | p |
26
+ entry = p.parse(*args)
27
+ return entry if entry
40
28
  end
41
29
  end
30
+
31
+ # Gets raised with raise_on_failed_server_detection set
32
+ class ParseError < RuntimeError
33
+ end
42
34
  end
43
35
 
@@ -0,0 +1,69 @@
1
+ # Represents an entry of the FTP list. Gets returned when you parse a list.
2
+ class Net::FTP::List::Entry
3
+
4
+ ALLOWED_ATTRIBUTES = [:raw, :basename, :dir, :file, :symlink, :mtime, :filesize, :device, :server_type] #:nodoc:
5
+
6
+ # Create a new entry object. The additional argument is the list of metadata keys
7
+ # that can be used on the object. By default just takes and set the raw list entry.
8
+ # Net::FTP::List.parse(raw_list_string) # => Net::FTP::List::Parser instance.
9
+ def initialize(raw_ls_line, optional_attributes = {}) #:nodoc:
10
+ @raw = raw_ls_line
11
+ optional_attributes.each_pair do |key, value|
12
+ raise ArgumentError, "#{key} is not supported" unless ALLOWED_ATTRIBUTES.include?(key)
13
+ instance_variable_set("@#{key}", value)
14
+ end
15
+ end
16
+
17
+ # The raw list entry string.
18
+ def raw
19
+ @raw ||= ''
20
+ end
21
+ alias_method :to_s, :raw
22
+
23
+ # The items basename (filename).
24
+ def basename
25
+ @basename ||= ''
26
+ end
27
+ alias name basename
28
+
29
+ # Looks like a directory, try CWD.
30
+ def dir?
31
+ !!(@dir ||= false)
32
+ end
33
+ alias directory? dir?
34
+
35
+ # Looks like a file, try RETR.
36
+ def file?
37
+ !!(@file ||= false)
38
+ end
39
+
40
+ # Looks like a symbolic link.
41
+ def symlink?
42
+ !!(@symlink ||= false)
43
+ end
44
+
45
+ # Looks like a device.
46
+ def device?
47
+ !!(@device ||= false)
48
+ end
49
+
50
+ # Returns the modification time of the file/directory or the current time if unknown
51
+ def mtime
52
+ @mtime || Time.now
53
+ end
54
+
55
+ # Returns the filesize of the entry or 0 for directorties
56
+ def filesize
57
+ @filesize || 0
58
+ end
59
+ alias size filesize
60
+
61
+ # Returns the detected server type if this entry
62
+ def server_type
63
+ @server_type || "Unknown"
64
+ end
65
+
66
+ def unknown?
67
+ @dir.nil? && @file.nil? && @symlink.nil? && @device.nil?
68
+ end
69
+ end
@@ -1,54 +1,38 @@
1
1
  require 'net/ftp/list/parser'
2
2
  require 'date'
3
3
 
4
- module Net
5
- class FTP
6
- module List
7
-
8
- # Parse Microsoft(NT) like FTP LIST entries.
9
- #
10
- # == MATCHES
11
- #
12
- # 06-25-07 01:08PM <DIR> etc
13
- # 11-27-07 08:45PM 23437 README.TXT
14
- #
15
- # == SYNOPSIS
16
- #
17
- # entry = Net::FTP::List::Microsoft.new('06-25-07 01:08PM <DIR> etc')
18
- # entry.dir? # => true
19
- # entry.basename # => 'etc'
20
- class Microsoft < Parser
21
-
22
- # Stolen straight from the ASF's commons Java FTP LIST parser library.
23
- # http://svn.apache.org/repos/asf/commons/proper/net/trunk/src/java/org/apache/commons/net/ftp/
24
- REGEXP = %r!
25
- ^\s*
26
- ([0-9\-:\/]{5,})\s+([0-9\-:]{3,}(?:[aApP][mM])?)\s+
27
- (?:(<DIR>)|([0-9]+))\s+
28
- (\S.*)
29
- \s*$
30
- !x
31
-
32
- # Parse a Microsoft(NT) like FTP LIST entries.
33
- def initialize(raw)
34
- super(raw)
35
- match = REGEXP.match(raw.strip) or raise ParserError
36
-
37
- @mtime = DateTime.strptime("#{match[1]} #{match[2]}", "%m-%d-%y %I:%M%p")
38
-
39
- if match[3] == '<DIR>'
40
- @dir = true
41
- else
42
- @filesize = match[4].to_i
43
- @file = true
44
- end
45
-
46
- # TODO: Permissions, users, groups, date/time.
47
-
48
- @basename = match[5]
49
- end
50
- end
51
-
52
- end
4
+ # Parse Microsoft(NT) like FTP LIST entries.
5
+ #
6
+ # == MATCHES
7
+ #
8
+ # 06-25-07 01:08PM <DIR> etc
9
+ # 11-27-07 08:45PM 23437 README.TXT
10
+ class Net::FTP::List::Microsoft < Net::FTP::List::Parser
11
+ # Stolen straight from the ASF's commons Java FTP LIST parser library.
12
+ # http://svn.apache.org/repos/asf/commons/proper/net/trunk/src/java/org/apache/commons/net/ftp/
13
+ REGEXP = %r!
14
+ ^\s*
15
+ ([0-9\-:\/]{5,})\s+([0-9\-:]{3,}(?:[aApP][mM])?)\s+
16
+ (?:(<DIR>)|([0-9]+))\s+
17
+ (\S.*)
18
+ \s*$
19
+ !x
20
+
21
+ # Parse a Microsoft(NT) like FTP LIST entries.
22
+ def self.parse(raw)
23
+ match = REGEXP.match(raw.strip) or return false
24
+
25
+ mtime = DateTime.strptime("#{match[1]} #{match[2]}", "%m-%d-%y %H:%M%p")
26
+ is_dir = match[3] == '<DIR>'
27
+ filesize = is_dir ? 0 : match[4].to_i
28
+
29
+ emit_entry(
30
+ raw,
31
+ :dir => is_dir,
32
+ :file => !is_dir,
33
+ :filesize => filesize,
34
+ :basename => match[5],
35
+ :mtime => mtime
36
+ )
53
37
  end
54
38
  end
@@ -1,54 +1,35 @@
1
1
  require 'net/ftp/list/parser'
2
2
  require 'time'
3
3
 
4
- module Net
5
- class FTP
6
- module List
7
-
8
- # Parse Netware like FTP LIST entries.
9
- #
10
- # == MATCHES
11
- #
12
- # d [RWCEAFMS] dpearce 512 Jun 27 23:46 public.www
13
- #
14
- # == SYNOPSIS
15
- #
16
- # entry = Net::FTP::List::Netware.new('d [RWCEAFMS] dpearce 512 Jun 27 23:46 public.www')
17
- # entry.dir? # => true
18
- # entry.basename # => 'public.www'
19
- class Netware < Parser
20
-
21
- # Stolen straight from the ASF's commons Java FTP LIST parser library.
22
- # http://svn.apache.org/repos/asf/commons/proper/net/trunk/src/java/org/apache/commons/net/ftp/
23
-
24
- REGEXP = %r!^
25
- (d|-){1}\s+
26
- \[(.*?)\]\s+
27
- (\S+)\s+(\d+)\s+
28
- (\S+\s+\S+\s+((\d+:\d+)|(\d{4})))
29
- \s+(.*)
30
- $!x
31
-
32
- # Parse a Netware like FTP LIST entries.
33
- def initialize(raw)
34
- super(raw)
35
- match = REGEXP.match(raw.strip) or raise ParserError
36
-
37
- @mtime = Time.parse(match[5])
38
- @filesize = match[4].to_i
39
-
40
- if match[1] == 'd'
41
- @dir = true
42
- else
43
- @file = true
44
- end
45
-
46
- # TODO: Permissions, users, groups, date/time.
47
-
48
- @basename = match[9]
49
- end
50
- end
51
-
52
- end
4
+ # Parse Netware like FTP LIST entries.
5
+ #
6
+ # == MATCHES
7
+ #
8
+ # d [RWCEAFMS] dpearce 512 Jun 27 23:46 public.www
9
+ class Net::FTP::List::Netware < Net::FTP::List::Parser
10
+ # Stolen straight from the ASF's commons Java FTP LIST parser library.
11
+ # http://svn.apache.org/repos/asf/commons/proper/net/trunk/src/java/org/apache/commons/net/ftp/
12
+ REGEXP = %r!^
13
+ (d|-){1}\s+
14
+ \[(.*?)\]\s+
15
+ (\S+)\s+(\d+)\s+
16
+ (\S+\s+\S+\s+((\d+:\d+)|(\d{4})))
17
+ \s+(.*)
18
+ $!x
19
+
20
+ # Parse a Netware like FTP LIST entries.
21
+ def self.parse(raw)
22
+ match = REGEXP.match(raw.strip) or return false
23
+
24
+ is_dir = match[1] == 'd'
25
+
26
+ emit_entry(
27
+ raw,
28
+ :mtime => Time.parse(match[5]),
29
+ :filesize => match[4].to_i,
30
+ :dir => is_dir,
31
+ :file => !is_dir,
32
+ :basename => match[9]
33
+ )
53
34
  end
54
35
  end
@@ -1,101 +1,28 @@
1
- module Net
2
- class FTP
3
- module List
1
+ # Abstract FTP LIST parser. It really just defines and documents the interface.
2
+ class Net::FTP::List::Parser
4
3
 
5
- # ParserError
6
- #
7
- # Raw entry couldn't be parsed for some reason.
8
- #
9
- # == TODO
10
- #
11
- # Get more specific with error messages.
12
- class ParserError < RuntimeError; end
4
+ @@parsers = []
13
5
 
14
- # Abstract FTP LIST parser.
15
- #
16
- # It really just defines and documents the interface.
17
- #
18
- # == Exceptions
19
- #
20
- # +ParserError+ -- Raw entry could not be parsed.
21
- class Parser
22
- @@parsers = []
23
-
24
- # Parse a raw FTP LIST line.
25
- #
26
- # By default just takes and set the raw list entry.
27
- #
28
- # Net::FTP::List.parse(raw_list_string) # => Net::FTP::List::Parser instance.
29
- def initialize(raw)
30
- @raw = raw
31
- end
32
-
33
- # The raw list entry string.
34
- def raw
35
- @raw ||= ''
36
- end
37
- alias_method :to_s, :raw
38
-
39
- # The items basename (filename).
40
- def basename
41
- @basename ||= ''
42
- end
43
-
44
- # Looks like a directory, try CWD.
45
- def dir?
46
- !!(@dir ||= false)
47
- end
48
-
49
- # Looks like a file, try RETR.
50
- def file?
51
- !!(@file ||= false)
52
- end
53
-
54
- # Looks like a symbolic link.
55
- def symlink?
56
- !!(@symlink ||= false)
57
- end
58
-
59
- def mtime
60
- @mtime
61
- end
62
-
63
- def filesize
64
- @filesize
65
- end
6
+ # Run a passed block with each parser in succession, from the most specific to the least
7
+ # specific. Will return the result of the block.
8
+ def self.with_each_parser(&blk) #:yields: parser
9
+ @@parsers.each(&blk)
10
+ end
66
11
 
67
- class << self
68
- # Acts as a factory.
69
- #
70
- # TODO: Having a class be both factory and abstract implementation seems a little nutty to me. If it ends up
71
- # too confusing or gives anyone the shits I'll move it.
72
- def inherited(klass) #:nodoc:
73
- @@parsers << klass
74
- end
12
+ # Automatically add an inheriting parser to the list of known parsers.
13
+ def self.inherited(klass) #:nodoc:
14
+ @@parsers.push(klass)
15
+ end
75
16
 
76
- # Factory method.
77
- #
78
- # Attempt to find a parser and parse a list item. At worst the item will return an Net::FTP::List::Unknown
79
- # instance. This may change in the future so that only parsable entries are kept.
80
- def parse(raw)
81
- @@parsers.reverse.each do |parser|
82
- begin
83
- return parser.new(raw)
84
- rescue ParserError
85
- next
86
- end
87
- end
88
- end
89
- end
17
+ # The main parse method. Return false from it if parsing fails (this is cheaper than raising an exception)
18
+ def self.parse(raw)
19
+ return false
20
+ end
90
21
 
91
- end
22
+ private
92
23
 
93
- # Unknown parser.
94
- #
95
- # If all other attempts to parse the entry fail this class will be returned. Only the +raw+ and +to_s+
96
- # methods will return anything useful.
97
- class Unknown < Parser
98
- end
99
- end
24
+ # Automatically adds the name of the parser class to the server_type field
25
+ def self.emit_entry(raw, extra_attributes)
26
+ Net::FTP::List::Entry.new raw, extra_attributes.merge(:server_type => to_s.split('::').pop)
100
27
  end
101
28
  end
@@ -0,0 +1,33 @@
1
+ require 'net/ftp/list/parser'
2
+
3
+ # Parse Rumpus FTP LIST entries.
4
+ #
5
+ # == MATCHES
6
+ # drwxr-xr-x folder 0 Nov 30 10:03 houdini
7
+ # -rw-r--r-- 0 101426 101426 Jun 7 2008 imap with spaces.rb
8
+ class Net::FTP::List::Rumpus < Net::FTP::List::Parser
9
+
10
+ REGEXP = %r!^
11
+ ([drwxr-]{10})\s+
12
+ (folder|0\s+\d+)\s+
13
+ (\d+)\s+
14
+ (\w+)\s+
15
+ (\d{1,2})\s+
16
+ (\d{2}:\d{2}|\d{4})\s+
17
+ (.+)
18
+ $!x
19
+
20
+ # Parse a Rumpus FTP LIST entry.
21
+ def self.parse(raw)
22
+ match = REGEXP.match(raw.strip) or return false
23
+
24
+ emit_entry(
25
+ raw,
26
+ :basename => match[7],
27
+ :mtime => Time.parse([match[4], match[5], match[6]].join(" ")),
28
+ :file => !(match[2] == "folder"),
29
+ :dir => (match[2] == "folder"),
30
+ :filesize => match[3].to_i
31
+ )
32
+ end
33
+ end
@@ -1,65 +1,66 @@
1
1
  require 'time'
2
2
  require 'net/ftp/list/parser'
3
3
 
4
- module Net
5
- class FTP
6
- module List
4
+ # Parse Unix like FTP LIST entries.
5
+ #
6
+ # == MATCHES
7
+ #
8
+ # drwxr-xr-x 4 steve group 4096 Dec 10 20:23 etc
9
+ # -rw-r--r-- 1 root other 531 Jan 29 03:26 README.txt
10
+ class Net::FTP::List::Unix < Net::FTP::List::Parser
7
11
 
8
- # Parse Unix like FTP LIST entries.
9
- #
10
- # == MATCHES
11
- #
12
- # drwxr-xr-x 4 steve group 4096 Dec 10 20:23 etc
13
- # -rw-r--r-- 1 root other 531 Jan 29 03:26 README.txt
14
- #
15
- # == SYNOPSIS
16
- #
17
- # entry = Net::FTP::List::Unix.new('drwxr-xr-x 4 steve group 4096 Dec 10 20:23 etc')
18
- # entry.dir? # => true
19
- # entry.basename # => 'etc'
20
- class Unix < Parser
12
+ # Stolen straight from the ASF's commons Java FTP LIST parser library.
13
+ # http://svn.apache.org/repos/asf/commons/proper/net/trunk/src/java/org/apache/commons/net/ftp/
14
+ REGEXP = %r{
15
+ ([pbcdlfmpSs-])
16
+ (((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\+?\s+
17
+ (\d+)\s+
18
+ (\S+)\s+
19
+ (?:(\S+(?:\s\S+)*)\s+)?
20
+ (?:\d+,\s+)?
21
+ (\d+)\s+
22
+ ((?:\d+[-/]\d+[-/]\d+)|(?:\S+\s+\S+))\s+
23
+ (\d+(?::\d+)?)\s+
24
+ (\S*)(\s*.*)
25
+ }x
21
26
 
22
- # Stolen straight from the ASF's commons Java FTP LIST parser library.
23
- # http://svn.apache.org/repos/asf/commons/proper/net/trunk/src/java/org/apache/commons/net/ftp/
24
- REGEXP = %r{
25
- ([bcdlfmpSs-])
26
- (((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))\+?\s+
27
- (\d+)\s+
28
- (\S+)\s+
29
- (?:(\S+(?:\s\S+)*)\s+)?
30
- (\d+)\s+
31
- ((?:\d+[-/]\d+[-/]\d+)|(?:\S+\s+\S+))\s+
32
- (\d+(?::\d+)?)\s+
33
- (\S*)(\s*.*)
34
- }x
27
+ ONE_YEAR = (60 * 60 * 24 * 365)
35
28
 
36
- # Parse a Unix like FTP LIST entries.
37
- def initialize(raw)
38
- super(raw)
39
- match = REGEXP.match(raw.strip) or raise ParserError
29
+ # Parse a Unix like FTP LIST entries.
30
+ def self.parse(raw)
31
+ match = REGEXP.match(raw.strip) or return false
40
32
 
41
- case match[1]
42
- when /d/ then @dir = true
43
- when /l/ then @symlink = true
44
- when /[f-]/ then @file = true
45
- when /[bc]/ then # Do nothing with devices for now.
46
- else ParserError 'Unknown LIST entry type.'
47
- end
33
+ dir, symlink, file, device = false, false, false, false
34
+ case match[1]
35
+ when /d/ then dir = true
36
+ when /l/ then symlink = true
37
+ when /[f-]/ then file = true
38
+ when /[psbc]/ then device = true
39
+ end
40
+ return false unless dir or symlink or file or device
48
41
 
49
- # TODO: Permissions, users, groups, date/time.
50
- @filesize = match[18].to_i
51
- @mtime = Time.parse("#{match[19]} #{match[20]}")
42
+ # TODO: Permissions, users, groups, date/time.
43
+ filesize = match[18].to_i
44
+ mtime = Time.parse("#{match[19]} #{match[20]}")
45
+ mtime -= ONE_YEAR if mtime > Time.now
52
46
 
53
- @basename = match[21].strip
47
+ basename = match[21].strip
54
48
 
55
- # filenames with spaces will end up in the last match
56
- @basename += match[22] unless match[22].nil?
49
+ # filenames with spaces will end up in the last match
50
+ basename += match[22] unless match[22].nil?
57
51
 
58
- # strip the symlink stuff we don't care about
59
- @basename.sub!(/\s+\->.+$/, '') if @symlink
60
- end
61
- end
52
+ # strip the symlink stuff we don't care about
53
+ basename.sub!(/\s+\->.+$/, '') if symlink
62
54
 
63
- end
55
+ emit_entry(
56
+ raw,
57
+ :dir => dir,
58
+ :file => file,
59
+ :device => device,
60
+ :symlink => symlink,
61
+ :filesize => filesize,
62
+ :basename => basename,
63
+ :mtime => mtime
64
+ )
64
65
  end
65
66
  end
@@ -0,0 +1,14 @@
1
+ require 'net/ftp/list/parser'
2
+
3
+ # If all other attempts to parse the entry fail this is the parser that is going to be used.
4
+ # It might be a good idea to fail loudly.
5
+ class Net::FTP::List::Unknown < Net::FTP::List::Parser
6
+ def self.parse(raw)
7
+ if Net::FTP::List.raise_on_failed_server_detection
8
+ raise Net::FTP::List::ParseError, "Could not parse #{raw} since none of the parsers was up to the task"
9
+ end
10
+
11
+ emit_entry(raw, {})
12
+ end
13
+ end
14
+
@@ -1,50 +1,57 @@
1
1
  # Generated by jeweler
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{net-ftp-list}
8
- s.version = "2.1.1"
8
+ s.version = "3.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Stateless Systems"]
12
- s.date = %q{2010-07-30}
12
+ s.date = %q{2011-01-09}
13
13
  s.email = %q{enquiries@statelesssystems.com}
14
14
  s.extra_rdoc_files = [
15
15
  "README.txt"
16
16
  ]
17
17
  s.files = [
18
- ".gitignore",
19
- "README.txt",
20
- "Rakefile",
21
- "VERSION.yml",
22
- "lib/net/ftp/list.rb",
23
- "lib/net/ftp/list/microsoft.rb",
24
- "lib/net/ftp/list/netware.rb",
25
- "lib/net/ftp/list/parser.rb",
26
- "lib/net/ftp/list/unix.rb",
27
- "net-ftp-list.gemspec",
28
- "test/test_net_ftp_list_microsoft.rb",
29
- "test/test_net_ftp_list_netware.rb",
30
- "test/test_net_ftp_list_unix.rb"
18
+ "README.txt",
19
+ "Rakefile",
20
+ "VERSION.yml",
21
+ "lib/net/ftp/list.rb",
22
+ "lib/net/ftp/list/entry.rb",
23
+ "lib/net/ftp/list/microsoft.rb",
24
+ "lib/net/ftp/list/netware.rb",
25
+ "lib/net/ftp/list/parser.rb",
26
+ "lib/net/ftp/list/rumpus.rb",
27
+ "lib/net/ftp/list/unix.rb",
28
+ "lib/net/ftp/list/unknown.rb",
29
+ "net-ftp-list.gemspec",
30
+ "test/test_net_ftp_list.rb",
31
+ "test/test_net_ftp_list_entry.rb",
32
+ "test/test_net_ftp_list_microsoft.rb",
33
+ "test/test_net_ftp_list_netware.rb",
34
+ "test/test_net_ftp_list_rumpus.rb",
35
+ "test/test_net_ftp_list_unix.rb"
31
36
  ]
32
37
  s.homepage = %q{http://github.com/stateless-systems/net-ftp-list}
33
- s.rdoc_options = ["--charset=UTF-8"]
34
38
  s.require_paths = ["lib"]
35
- s.rubygems_version = %q{1.3.5}
39
+ s.rubygems_version = %q{1.3.7}
36
40
  s.summary = %q{Parse FTP LIST command output.}
37
41
  s.test_files = [
42
+ "test/test_net_ftp_list.rb",
43
+ "test/test_net_ftp_list_entry.rb",
38
44
  "test/test_net_ftp_list_microsoft.rb",
39
- "test/test_net_ftp_list_unix.rb",
40
- "test/test_net_ftp_list_netware.rb"
45
+ "test/test_net_ftp_list_netware.rb",
46
+ "test/test_net_ftp_list_rumpus.rb",
47
+ "test/test_net_ftp_list_unix.rb"
41
48
  ]
42
49
 
43
50
  if s.respond_to? :specification_version then
44
51
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
45
52
  s.specification_version = 3
46
53
 
47
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
54
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
48
55
  else
49
56
  end
50
57
  else
@@ -0,0 +1,26 @@
1
+ require 'test/unit'
2
+ require 'net/ftp/list'
3
+
4
+ class TestNetFTPList < Test::Unit::TestCase
5
+
6
+ def test_all
7
+ one = Net::FTP::List.parse('drwxr-xr-x 4 user group 4096 Dec 10 20:23 etc')
8
+ assert_kind_of Net::FTP::List::Entry, one
9
+ assert one.dir?
10
+ assert !one.file?
11
+
12
+ two = Net::FTP::List.parse("++ unknown garbage +++")
13
+ assert_kind_of Net::FTP::List::Entry, two
14
+ assert two.unknown?
15
+ assert_equal '', two.basename
16
+ end
17
+
18
+ def test_raise_when_flag_set
19
+ Net::FTP::List.raise_on_failed_server_detection = true
20
+ assert_raise(Net::FTP::List::ParseError) do
21
+ Net::FTP::List.parse("++ unknown garbage +++")
22
+ end
23
+ ensure
24
+ Net::FTP::List.raise_on_failed_server_detection = false
25
+ end
26
+ end
@@ -0,0 +1,25 @@
1
+ require 'test/unit'
2
+ require 'net/ftp/list'
3
+
4
+ class TestNetFTPEntry < Test::Unit::TestCase
5
+
6
+ def test_raise_on_unknown_options
7
+ assert_raise(ArgumentError) { Net::FTP::List::Entry.new("foo", {:bar => "baz"}) }
8
+ end
9
+
10
+ def test_default_values
11
+ e = Net::FTP::List::Entry.new('')
12
+ assert_equal 0, e.filesize
13
+ assert_equal 0, e.size
14
+ assert_equal '', e.basename
15
+ assert_equal '', e.name
16
+ assert e.unknown?
17
+ assert !e.dir?
18
+ assert !e.directory?
19
+ assert !e.file?
20
+ assert !e.symlink?
21
+ assert_kind_of Time, e.mtime
22
+ assert_equal "Unknown", e.server_type
23
+ end
24
+
25
+ end
@@ -4,18 +4,17 @@ require 'net/ftp/list'
4
4
  class TestNetFTPListMicrosoft < Test::Unit::TestCase
5
5
 
6
6
  def setup
7
- # DATE TIME DIR SIZE NAME
8
7
  @dir = Net::FTP::List.parse('06-25-07 01:08PM <DIR> etc')
9
8
  @file = Net::FTP::List.parse('11-27-07 08:45PM 23437 README.TXT')
10
9
  end
11
10
 
12
11
  def test_parse_new
13
- assert_instance_of Net::FTP::List::Microsoft, @dir, 'LIST M$ directory'
14
- assert_instance_of Net::FTP::List::Microsoft, @file, 'LIST M$ file'
12
+ assert_equal "Microsoft", @dir.server_type, 'LIST M$ directory'
13
+ assert_equal "Microsoft", @file.server_type, 'LIST M$ directory'
15
14
  end
16
15
 
17
16
  def test_rubbish_lines
18
- assert_instance_of Net::FTP::List::Unknown, Net::FTP::List.parse("++ bah! ++")
17
+ assert_instance_of Net::FTP::List::Entry, Net::FTP::List.parse("++ bah! ++")
19
18
  end
20
19
 
21
20
  def test_ruby_microsoft_mtime
@@ -36,7 +35,12 @@ class TestNetFTPListMicrosoft < Test::Unit::TestCase
36
35
  end
37
36
 
38
37
  def test_filesize
39
- assert @dir.filesize.nil?
38
+ assert_equal 0, @dir.filesize
40
39
  assert_equal 23437, @file.filesize
41
40
  end
41
+
42
+ def test_zero_hour
43
+ file = Net::FTP::List.parse('10-15-09 00:34AM <DIR> aspnet_client')
44
+ assert_equal 1255566840.to_s, file.mtime.strftime('%s')
45
+ end
42
46
  end
@@ -9,12 +9,8 @@ class TestNetFTPListNetware < Test::Unit::TestCase
9
9
  end
10
10
 
11
11
  def test_parse_new
12
- assert_instance_of Net::FTP::List::Netware, @dir, 'LIST Netware directory'
13
- assert_instance_of Net::FTP::List::Netware, @file, 'LIST Netware file'
14
- end
15
-
16
- def test_rubbish_lines
17
- assert_instance_of Net::FTP::List::Unknown, Net::FTP::List.parse("++ bah! ++")
12
+ assert_equal "Netware", @dir.server_type, 'LIST Netware directory'
13
+ assert_equal "Netware", @file.server_type, 'LIST Netware file'
18
14
  end
19
15
 
20
16
  def test_ruby_netware_mtime
@@ -0,0 +1,40 @@
1
+ require 'test/unit'
2
+ require 'net/ftp/list'
3
+
4
+ class TestNetFTPListRumpus < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @dir = Net::FTP::List.parse 'drwxrwxrwx folder 0 Nov 16 22:12 Alias'
8
+ @file = Net::FTP::List.parse '-rw-r--r-- 0 101426 101426 Jun 7 2008 imap with spaces.rb'
9
+ end
10
+
11
+ def test_parsed
12
+ assert_equal "Rumpus", @dir.server_type, 'LIST Rumpus directory'
13
+
14
+ ## TODO: this rumpus file is getting picked up as unix, which if you check
15
+ ## how it looks above, it looks like unix to me, i dunno how to fix it.
16
+ #assert_equal "Rumpus", @file.server_type, 'LIST Rumpus file with spaces'
17
+ end
18
+
19
+ def test_ruby_unix_like_date
20
+ assert_equal Time.parse("Nov 16 22:12"), @dir.mtime
21
+ assert_equal Time.parse("Jun 7 2008"), @file.mtime
22
+ end
23
+
24
+ def test_dir
25
+ assert_equal 'Alias', @dir.basename
26
+ assert !@dir.file?
27
+ assert @dir.dir?
28
+ end
29
+
30
+ def test_file
31
+ assert_equal 'imap with spaces.rb', @file.basename
32
+ assert @file.file?
33
+ assert !@file.dir?
34
+ end
35
+
36
+ def test_filesize
37
+ assert_equal 0, @dir.filesize
38
+ assert_equal 101426, @file.filesize
39
+ end
40
+ end
@@ -3,31 +3,49 @@ require 'net/ftp/list'
3
3
 
4
4
  class TestNetFTPListUnix < Test::Unit::TestCase
5
5
 
6
+ ONE_YEAR = (60 * 60 * 24 * 365)
7
+
8
+ FIRST_MINUTE_OF_YEAR = "Jan 1 00:00"
9
+ LAST_MINUTE_OF_YEAR = "Dec 31 23:59"
10
+ OTHER_RELATIVE_TIME = "Mar 11 07:57"
11
+ SYMBOLIC_LINK_TIME = "Oct 30 15:26"
12
+ ABSOLUTE_DATE = "Feb 15 2008"
13
+
6
14
  def setup
7
- @dir = Net::FTP::List.parse 'drwxr-xr-x 4 user group 4096 Dec 10 20:23 etc'
8
- @file = Net::FTP::List.parse '-rw-r--r-- 1 root other 531 Jan 29 03:26 README'
9
- @other_dir = Net::FTP::List.parse 'drwxr-xr-x 8 1791 600 4096 Mar 11 07:57 forums'
10
- @spaces = Net::FTP::List.parse 'drwxrwxr-x 2 danial danial 72 May 23 12:52 spaces suck'
11
- @symlink = Net::FTP::List.parse 'lrwxrwxrwx 1 danial danial 4 Apr 30 15:26 bar -> /etc'
12
- @older_date = Net::FTP::List.parse '-rwxrwxrwx 1 owner group 154112 Feb 15 2008 participando.xls'
15
+ @dir = Net::FTP::List.parse "drwxr-xr-x 4 user group 4096 #{FIRST_MINUTE_OF_YEAR} etc" rescue nil
16
+ @file = Net::FTP::List.parse "-rw-r--r-- 1 root other 531 #{LAST_MINUTE_OF_YEAR} README" rescue nil
17
+ @other_dir = Net::FTP::List.parse "drwxr-xr-x 8 1791 600 4096 #{OTHER_RELATIVE_TIME} forums" rescue nil
18
+ @spaces = Net::FTP::List.parse 'drwxrwxr-x 2 danial danial 72 May 23 12:52 spaces suck' rescue nil
19
+ @symlink = Net::FTP::List.parse "lrwxrwxrwx 1 danial danial 4 #{SYMBOLIC_LINK_TIME} bar -> /etc" rescue nil
20
+ @older_date = Net::FTP::List.parse "-rwxrwxrwx 1 owner group 154112 #{ABSOLUTE_DATE} participando.xls" rescue nil
21
+ @block_dev = Net::FTP::List.parse 'brw-r----- 1 root disk 1, 0 Apr 13 2006 ram0' rescue nil
22
+ @char_dev = Net::FTP::List.parse 'crw-rw-rw- 1 root root 1, 3 Apr 13 2006 null' rescue nil
23
+ @socket_dev = Net::FTP::List.parse 'srw-rw-rw- 1 root root 0 Aug 20 14:15 log' rescue nil
24
+ @pipe_dev = Net::FTP::List.parse 'prw-r----- 1 root adm 0 Nov 22 10:30 xconsole' rescue nil
13
25
  end
14
26
 
15
27
  def test_parse_new
16
- assert_instance_of Net::FTP::List::Unix, @dir, 'LIST unixish directory'
17
- assert_instance_of Net::FTP::List::Unix, @file, 'LIST unixish file'
18
- assert_instance_of Net::FTP::List::Unix, @other_dir, 'LIST unixish directory'
19
- assert_instance_of Net::FTP::List::Unix, @spaces, 'LIST unixish directory with spaces'
20
- assert_instance_of Net::FTP::List::Unix, @symlink, 'LIST unixish symlink'
21
- end
22
-
23
- def test_rubbish_lines
24
- assert_instance_of Net::FTP::List::Unknown, Net::FTP::List.parse("++ bah! ++")
28
+ assert_equal "Unix", @dir.server_type, 'LIST unixish directory'
29
+ assert_equal "Unix", @file.server_type, 'LIST unixish file'
30
+ assert_equal "Unix", @other_dir.server_type, 'LIST unixish directory'
31
+ assert_equal "Unix", @spaces.server_type, 'LIST unixish directory with spaces'
32
+ assert_equal "Unix", @symlink.server_type, 'LIST unixish symlink'
33
+ assert_equal "Unix", @block_dev.server_type, 'LIST unix block device'
34
+ assert_equal "Unix", @char_dev.server_type, 'LIST unix char device'
35
+ assert_equal "Unix", @socket_dev.server_type, 'LIST unix socket device'
36
+ assert_equal "Unix", @pipe_dev.server_type, 'LIST unix socket device'
25
37
  end
26
38
 
27
39
  def test_ruby_unix_like_date
28
- assert_equal Time.parse("Mar 11 07:57"), @other_dir.mtime
29
- assert_equal Time.parse("Apr 30 15:26"), @symlink.mtime
30
- assert_equal Time.parse("Feb 15 2008"), @older_date.mtime
40
+ {
41
+ FIRST_MINUTE_OF_YEAR => @dir,
42
+ LAST_MINUTE_OF_YEAR => @file,
43
+ OTHER_RELATIVE_TIME => @other_dir,
44
+ SYMBOLIC_LINK_TIME => @symlink,
45
+ ABSOLUTE_DATE => @older_date
46
+ }.each do |date_and_time, parsed_entry|
47
+ assert_equal parse_adjust_date_and_time(date_and_time), parsed_entry.send(:mtime)
48
+ end
31
49
  end
32
50
 
33
51
  def test_ruby_unix_like_dir
@@ -67,4 +85,32 @@ class TestNetFTPListUnix < Test::Unit::TestCase
67
85
  assert_equal 4, @symlink.filesize
68
86
  assert_equal 154112, @older_date.filesize
69
87
  end
88
+
89
+ def test_unix_block_device
90
+ assert_equal 'ram0', @block_dev.basename
91
+ assert @block_dev.device?
92
+ end
93
+
94
+ def test_unix_char_device
95
+ assert_equal 'null', @char_dev.basename
96
+ assert @char_dev.device?
97
+ end
98
+
99
+ def test_unix_socket_device
100
+ assert_equal 'log', @socket_dev.basename
101
+ assert @socket_dev.device?
102
+ end
103
+
104
+ def test_unix_pipe_device
105
+ assert_equal 'xconsole', @pipe_dev.basename
106
+ assert @pipe_dev.device?
107
+ end
108
+
109
+
110
+ private
111
+ def parse_adjust_date_and_time(date_and_time)
112
+ parsed_time = Time.parse(date_and_time)
113
+ parsed_time -= ONE_YEAR if parsed_time > Time.now
114
+ parsed_time
115
+ end
70
116
  end
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net-ftp-list
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ prerelease: false
5
+ segments:
6
+ - 3
7
+ - 2
8
+ - 0
9
+ version: 3.2.0
5
10
  platform: ruby
6
11
  authors:
7
12
  - Stateless Systems
@@ -9,7 +14,7 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-07-30 00:00:00 +10:00
17
+ date: 2011-01-09 00:00:00 +11:00
13
18
  default_executable:
14
19
  dependencies: []
15
20
 
@@ -22,48 +27,60 @@ extensions: []
22
27
  extra_rdoc_files:
23
28
  - README.txt
24
29
  files:
25
- - .gitignore
26
30
  - README.txt
27
31
  - Rakefile
28
32
  - VERSION.yml
29
33
  - lib/net/ftp/list.rb
34
+ - lib/net/ftp/list/entry.rb
30
35
  - lib/net/ftp/list/microsoft.rb
31
36
  - lib/net/ftp/list/netware.rb
32
37
  - lib/net/ftp/list/parser.rb
38
+ - lib/net/ftp/list/rumpus.rb
33
39
  - lib/net/ftp/list/unix.rb
40
+ - lib/net/ftp/list/unknown.rb
34
41
  - net-ftp-list.gemspec
42
+ - test/test_net_ftp_list.rb
43
+ - test/test_net_ftp_list_entry.rb
35
44
  - test/test_net_ftp_list_microsoft.rb
36
45
  - test/test_net_ftp_list_netware.rb
46
+ - test/test_net_ftp_list_rumpus.rb
37
47
  - test/test_net_ftp_list_unix.rb
38
48
  has_rdoc: true
39
49
  homepage: http://github.com/stateless-systems/net-ftp-list
40
50
  licenses: []
41
51
 
42
52
  post_install_message:
43
- rdoc_options:
44
- - --charset=UTF-8
53
+ rdoc_options: []
54
+
45
55
  require_paths:
46
56
  - lib
47
57
  required_ruby_version: !ruby/object:Gem::Requirement
58
+ none: false
48
59
  requirements:
49
60
  - - ">="
50
61
  - !ruby/object:Gem::Version
62
+ segments:
63
+ - 0
51
64
  version: "0"
52
- version:
53
65
  required_rubygems_version: !ruby/object:Gem::Requirement
66
+ none: false
54
67
  requirements:
55
68
  - - ">="
56
69
  - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
57
72
  version: "0"
58
- version:
59
73
  requirements: []
60
74
 
61
75
  rubyforge_project:
62
- rubygems_version: 1.3.5
76
+ rubygems_version: 1.3.7
63
77
  signing_key:
64
78
  specification_version: 3
65
79
  summary: Parse FTP LIST command output.
66
80
  test_files:
81
+ - test/test_net_ftp_list.rb
82
+ - test/test_net_ftp_list_entry.rb
67
83
  - test/test_net_ftp_list_microsoft.rb
68
- - test/test_net_ftp_list_unix.rb
69
84
  - test/test_net_ftp_list_netware.rb
85
+ - test/test_net_ftp_list_rumpus.rb
86
+ - test/test_net_ftp_list_unix.rb
data/.gitignore DELETED
@@ -1,7 +0,0 @@
1
- *.sw?
2
- .DS_Store
3
- coverage
4
- rdoc
5
- pkg
6
- .idea/*
7
- .idea/**/*