Is there any object-oriented File class in ruby?

I am very new to Ruby and my question is about trying to understand
why Ruby is often described as a "pure object-oriented language", when
the core library seems to be quite procedural.

For example, the class File seems to have a big bunch of procedural
functions (or static methods, or whatever you want to call them) that
needs the filename to be provided as a parameter.

The File class in java is a much better OO class for managing files:
http://java.sun.com/j2se/1.5.0/docs/api/java/io/File.html
than the following ruby class:
http://ruby-doc.org/core/classes/File.html

For example, the ruby method File.basename is documented as only
supporting forward slashes, regardless of the local file system.
File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb"
Essentially, this seems to be not much more than a string parsing
function with no OO abstraction that represents a file object.
Compare this with doing the same thing with java:
File f = new File("/home/gumby/work/ruby.rb"); // or new File("C:\\home
\\gumby\\work\\ruby.rb");
f.getName() #=> "ruby.rb"

Now my question is what have I been missing here ?
I mean, is there any other much better File class somewhere in the
Ruby core that is more pure OO, or otherwise why is a language with a
CORE procedural "class" library described as being a pure oo
language ?

/ Tom

tom_33 wrote:

I am very new to Ruby and my question is about trying to understand
why Ruby is often described as a "pure object-oriented language", when
the core library seems to be quite procedural.
  <snip>
  Now my question is what have I been missing here ?
I mean, is there any other much better File class somewhere in the
Ruby core that is more pure OO, or otherwise why is a language with a
CORE procedural "class" library described as being a pure oo
language ?

/ Tom

You seem to only be looking at the class methods for File, which are basically utilities. Most of the real functionality is in the IO[1] class, File's superclass.

-Justin

[1]class IO - RDoc Documentation

tom_33 wrote:

I am very new to Ruby and my question is about trying to understand
why Ruby is often described as a "pure object-oriented language", when
the core library seems to be quite procedural.

For example, the class File seems to have a big bunch of procedural
functions (or static methods, or whatever you want to call them) that
needs the filename to be provided as a parameter.

The File class in java is a much better OO class for managing files:
http://java.sun.com/j2se/1.5.0/docs/api/java/io/File.html
than the following ruby class:
class File - RDoc Documentation

For example, the ruby method File.basename is documented as only
supporting forward slashes, regardless of the local file system.
File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb"
Essentially, this seems to be not much more than a string parsing
function with no OO abstraction that represents a file object.
Compare this with doing the same thing with java:
File f = new File("/home/gumby/work/ruby.rb"); // or new File("C:\\home
\\gumby\\work\\ruby.rb");
f.getName() #=> "ruby.rb"

Now my question is what have I been missing here ?
I mean, is there any other much better File class somewhere in the
Ruby core that is more pure OO, or otherwise why is a language with a
CORE procedural "class" library described as being a pure oo
language ?

/ Tom

Look at this code:

class A
  def hi
    puts 'hi'
  end
end

class B
  def B.hello
    puts 'hello'
  end
end

a = A.new
a.hi

B.hello

--output:--
hi
hello

Personally, I do not like the formal nature of class B. I prefer the
friendlier, more personable class A. As a result, I do not consider
class B to be object oriented.

Is that a logical conclusion?

Let's try this:

def hi
  puts 'hi'
end

def hello
  puts 'hi mate'
end

hi
hello

--output:--
hi
hi mate

I consider that output superior, therefore I believe that code is more
object oriented. Is that a logical conclusion?

···

--
Posted via http://www.ruby-forum.com/\.

For example, the ruby method File.basename is documented as only
supporting forward slashes, regardless of the local file system.
File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb"
Essentially, this seems to be not much more than a string parsing
function with no OO abstraction that represents a file object.
Compare this with doing the same thing with java:
File f = new File("/home/gumby/work/ruby.rb"); // or new File("C:\\home
\\gumby\\work\\ruby.rb");
f.getName() #=> "ruby.rb"

File is an OO abstraction and the fact that you don't see explicit support for alternative path separators does not bear on object orientedness. Consider this:

class WinFile < File
   def self.basename(filename, suffix ='')
     File.basename(filename.gsub(/\\/, '/'), suffix)
   end
end

That allows you to use WinFile everywhere you might have used File, complete with File's attributes, collections, iterators, and so on. It sounds like you are more *used* to Java's implementation of this class.

The reason for the "pure" adjective is that everything is derived from a base class, Object. Fixnum, String, File, everything. So anything that works on Object works on all of these. Try this:

irb
>> 1.public_methods
# long list of methods follows
>> 1.public_methods - Object.public_methods
# shorter list of methods belonging to Fixnum. How do we know?
>> 1.class
=> Fixnum

This kind of introspection and single-root object-orientation is much more difficult in more static languages and allows for much of the "magic" of Ruby.

···

On Feb 19, 2008, at 2:45 PM, tom_33 wrote:

It is described as 'pure' because almost all actions are a side-effect of sending a message to an object. In your example

    File.basename('/dir/file')

File is the object, basename is the message, and '/dir/file' is an argument (an instance of String). The most obvious example of the pervasiveness of this pattern is methods on integers:

    3.next # 4
    3.to_s(2) # "11", 3 as a string of binary digits
    (-3).abs # 3 the absolute value of -3
    (3.1415).floor # float value rounded down to integer

Many static syntactical constructs also have a dynamic/method based interface:

# subclass A statically

class A < B
   def foo
     42
   end
end

# subclass A dynamically

class_b = Class.new(A) {
   def foo
     42
   end
}

A big milestone in learning Ruby is to fully understand what it means for a class to be an object at runtime. With regard to the methods you were looking at. If you think of File as an object representing the file system then:

   File.basename(path) # file system parses path
   File.open(path) # file system looks up path and returns file instance

There is also Pathname, a class for manipulating file path strings and looking up file properties. It provides a unifying interface to other classes such as File, Dir, FileTests, String, and so on.

path = Pathname.new("/etc")
path.directory? # consults filesystem to see if "/etc" is a directory
path.atime # consutls filesystem to get atime of "/etc"

It is also important to realize that Ruby is a practical language in that there is often more than one way to skin a cat with Ruby as opposed to a 'one correct way'. So you can muck around with strings and regular expressions to parse path names or use File or use Pathname or roll your own class.

Gary Wright

···

On Feb 19, 2008, at 5:45 PM, tom_33 wrote:

Now my question is what have I been missing here ?
I mean, is there any other much better File class somewhere in the
Ruby core that is more pure OO, or otherwise why is a language with a
CORE procedural "class" library described as being a pure oo
language ?

I am very new to Ruby and my question is about trying to understand
why Ruby is often described as a "pure object-oriented language", when
the core library seems to be quite procedural.

It is a pure object-oriented language because everything is an object,
(even, e.g., things like Fixnum), this contrasts with, e.g., Java,
where certain primitive types are not objects.

For example, the class File seems to have a big bunch of procedural
functions (or static methods, or whatever you want to call them) that
needs the filename to be provided as a parameter.

They are called "Class methods" (because, really, they are just
regular instance methods where the receiver happens to be an instance
of class Class.)

And, yes, the class File has a lot of those, because there are a lot
of times when a program will want to get "one shot" information about
a file. You might also note, however, that many of them have
corresponding instance methods either on class File or class
File::Stat, so if you have an existing File instance, so you can do:

File.atime("/home/jsmith/myfile")
or File.new("/home/jsmith/myfile").atime

File.executable?("/home/jsmith/myfile")
or File.new("/home/jsmith/myfile").stat.executable?

Which way is most appropriate in any given use will depend on whether
there is more that you want to do with the file. There is no reason to
create a new file object and keep it around until it gets garbage
collected if you are just doing a one-shot request and don't need to
do anything more with the same file. As is often the case in Ruby,
there is more than one way to do it: and all of them are object
oriented.

For example, the ruby method File.basename is documented as only
supporting forward slashes, regardless of the local file system.
File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb"

The documentation is incorrect.

irb(main):049:0> VERSION
=> "1.8.6"
irb(main):050:0> File.basename("C:\\home\\gumby\\work\\ruby.rb")
=> "ruby.rb"

Essentially, this seems to be not much more than a string parsing
function with no OO abstraction that represents a file object.

Yes, File.basename *is* a string parsing function.

Compare this with doing the same thing with java:
File f = new File("/home/gumby/work/ruby.rb"); // or new File("C:\\home
\\gumby\\work\\ruby.rb");
f.getName() #=> "ruby.rb"

Which also seems to be a string parsing function with no necessary OO
abstraction. Handling a variety of path separators is orthogonal to
whether there is OO abstraction going on.

Now my question is what have I been missing here ?

It seems to me the IO#stat and File#lstat methods, and the File::Stat
class, among other things.

···

On Feb 19, 2008 2:45 PM, tom_33 <tomjbr.56770318@bloglines.com> wrote:

I too once thought exactly as you do. I still think it would probably
be best if File didn't have all those class methods. In reality, I
think what you're looking for is the Pathname class. In my mind, a
Pathname is a file reference, it has all the appropriate methods of a
file like mtime or directory?. A File, on the other hand, is an IO
stream. An IO stream has no concept of mtime or basename, it is for
reading and writing, and has no business with such methods. The real
shame in my mind is that File.new doesn't accept a pathname as a first
parameter, only a string.

Daniel Brumbaugh Keeney

···

On Feb 19, 2008 4:45 PM, tom_33 <tomjbr.56770318@bloglines.com> wrote:

For example, the class File seems to have a big bunch of procedural
functions (or static methods, or whatever you want to call them) that
needs the filename to be provided as a parameter.

For example, the ruby method File.basename is documented as only
supporting forward slashes, regardless of the local file system.
File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb"
Essentially, this seems to be not much more than a string parsing
function with no OO abstraction that represents a file object.
Compare this with doing the same thing with java:
File f = new File("/home/gumby/work/ruby.rb"); // or new File("C:\\home
\\gumby\\work\\ruby.rb");
f.getName() #=> "ruby.rb"

Now my question is what have I been missing here ?
I mean, is there any other much better File class somewhere in the
Ruby core that is more pure OO, or otherwise why is a language with a
CORE procedural "class" library described as being a pure oo
language ?

/ Tom

7stud -- wrote:

tom_33 wrote:

I am very new to Ruby and my question is about trying to understand
why Ruby is often described as a "pure object-oriented language", when
the core library seems to be quite procedural.

For example, the class File seems to have a big bunch of procedural
functions (or static methods, or whatever you want to call them) that
needs the filename to be provided as a parameter.

The File class in java is a much better OO class for managing files:
http://java.sun.com/j2se/1.5.0/docs/api/java/io/File.html
than the following ruby class:
class File - RDoc Documentation

For example, the ruby method File.basename is documented as only
supporting forward slashes, regardless of the local file system.
File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb"
Essentially, this seems to be not much more than a string parsing
function with no OO abstraction that represents a file object.
Compare this with doing the same thing with java:
File f = new File("/home/gumby/work/ruby.rb"); // or new File("C:\\home
\\gumby\\work\\ruby.rb");
f.getName() #=> "ruby.rb"

Now my question is what have I been missing here ?
I mean, is there any other much better File class somewhere in the
Ruby core that is more pure OO, or otherwise why is a language with a
CORE procedural "class" library described as being a pure oo
language ?

/ Tom

I just wanted to add: there are many bad implementations in ruby. In
addition, there are many bad programmers that badly implement
ruby--check out just about any thread on this forum. A lot of
solutions(most?) will string together 3 or 4 ruby method calls in a one
liner with a couple of regex's sprinkled in for good measure. As far as
I can tell, not many people know how to write clear efficient ruby code.
Of course their battle cry is: ruby is so inefficient anyway, what does
it matter if I write inefficient and obfuscated code.

···

--
Posted via http://www.ruby-forum.com/\.

In addition, there are many bad programmers that badly implement
ruby--check out just about any thread on this forum. [...]
As far as I can tell, not many people know how to write clear
efficient ruby code.

There are also a few trolls that delight in every chance to bash on ruby
and other ruby-ist's they can get ... right 7stud? But I agree on the
obfuscated part, for the following reason - I think a beautiful language
like ruby, and anyone writing in it, should not try to strive to write
ugly
code. We already have a language that does this part, and as far as I
can
tell it always tried to be a practical language without caring much
about
elegance.

As to the specific question of tom_33 about File class not being
"object oriented", I assume this in part lies with the separation of
tasks, i.e. if you look at FileUtils and its abilities, and class Dir.
I sometimes confuse whether to use File.exist? or File.exists?
or Dir.exists? or Dir.exist? anyway. (But you can use your
own class and make it "object oriented" super easily. This is one of
ruby's great points.)

Personally, I do not know why there is this separation (with FileUtils),
but I am quite sure that there was a reason for it.

···

--
Posted via http://www.ruby-forum.com/\.

That works in 1.9. In fact File.new will accept any argument the implements #to_path, which should return the string to be passed to the OS.

irb-1.9> File.new(Pathname.new('/etc/motd'))
=> #<File:/etc/motd>

···

On Feb 19, 2008, at 7:25 PM, Daniel Brumbaugh Keeney wrote:

The real
shame in my mind is that File.new doesn't accept a pathname as a first
parameter, only a string.

Christopher Dicely wrote:

The documentation is incorrect.

irb(main):049:0> VERSION
=> "1.8.6"
irb(main):050:0> File.basename("C:\\home\\gumby\\work\\ruby.rb")
=> "ruby.rb"

irb(main):001:0> VERSION
=> "1.8.6"
irb(main):002:0> File.basename("C:\\home\\gumby\\work\\ruby.rb")
=> "C:\\home\\gumby\\work\\ruby.rb"
irb(main):003:0>

···

--
Posted via http://www.ruby-forum.com/\.

> Essentially, this seems to be not much more than a string parsing
> function with no OO abstraction that represents a file object.

Yes, File.basename *is* a string parsing function.

> Compare this with doing the same thing with java:
> File f = new File("/home/gumby/work/ruby.rb"); // or new File("C:\\home
> \\gumby\\work\\ruby.rb");
> f.getName() #=> "ruby.rb"

Which also seems to be a string parsing function with no necessary OO
abstraction. Handling a variety of path separators is orthogonal to
whether there is OO abstraction going on.

Yes, you are right and internally the implemention of the java method
will need to parse the string somehow.
However, an important difference with ruby File class and the java
File class is that the java class provides a cohesive unit of instance
methods that encapsulates a file path, without having to provide a
string as parameter to every method.
Since the ruby class method "File.basename(filename)" is nothing but a
string parsing method it does IMHO not provide much useful value over
instead having a class method such as
"String.getStringPartAfterLastSlash(anyStringIncludingSomeSlash)"
or
"String.getStringPartAfterLastOccuranceOfSpecifiedCharacter(anyString,
someCharacter)".

Anyway, I have found what I was looking for in another reponse in this
thread:

Now my question is what have I been missing here ?
I mean, is there any other much better File class somewhere in the
Ruby core that is more pure OO ...

There is also Pathname, a class for manipulating file path strings
and looking up file properties.

Yes, that was indeed the kind of class I was looking for.
Obviously Ruby supports a procedural invocation style of using class
methods on the File class (the same way you would do it with non-oo-
language such as C, i.e. providing the same parameters over and over
again since there is no object that can encapsulate it in a
constructor call).

For example, if you would want to implement a methods that renames
files that are old and big (for some reason) then you would do this
kind of stuff with the File class:

if File.size(file_name) > someSizeLimit and File.mtime(file_name) <
someTimeLimit then
  ... do some string manipulation to extract the filename part from the
full path
  ... and also extract the directory part ...
  new_name = "big_old_file_" + fileNamePart
  new_nameWithFullPath = directoryPart + "/" + new_name
  File.rename(file_name, new_nameWithFullPath)
end

But with the much better Pathname class you can get an object with
instance methods:

path = Pathname.new(file_name)
if path.size() > someSizeLimit and path.mtime() < someTimeLimit then
  directory = path.parent
  fileNamePart = path.basename
  new_name = "big_old_file_" + fileNamePart
  # below file separator concatenation seems to be automatically
included if needed:
  newPath = directory + new_name
  path.rename(newPath)
end

There are two things that are better with the above code that uses
Pathname instead of File:
(1) You do not have to keep sending the same path string to the
methods but in can be encapsulated and memorized by the Pathname
instance.
(2) You do not need to extract (and concatenate with separators) the
directory part and the filename part through low level string parsing.

Lastly, I just want to complain a little bit about the documentation
of the File class, and hope that someone with write access to the
following page:
http://www.ruby-doc.org/core/classes/File.html
will update it with a reference to the Pathname class, from the the
description section in the beginning.
Without such a reference, it is likely that other people will use the
File class methods, without finding the Pathname class and its nice
instance methods.
Actually, I do not only think it should be mentioned, but it should be
encouraged to use them instead of the File class methods.

···

On Feb 20, 12:52 am, Christopher Dicely <cmdic...@gmail.com> wrote:
On Feb 19, 11:40 pm, tom_33 <tomjbr.56770...@bloglines.com> wrote:
On Feb 20, 12:37 am, Gary Wright <gwtm...@mac.com> wrote:

On Feb 19, 2008, at 5:45 PM, tom_33 wrote:

I am on Windows XP:

irb(main):001:0> File.basename("C:\\home\\gumby\\work\\ruby.rb")
=> "ruby.rb"
irb(main):002:0> VERSION
=> "1.8.6"

···

On Wed, Feb 20, 2008 at 8:09 AM, 7stud -- <bbxx789_05ss@yahoo.com> wrote:

Christopher Dicely wrote:
> The documentation is incorrect.
>
> irb(main):049:0> VERSION
> => "1.8.6"
> irb(main):050:0> File.basename("C:\\home\\gumby\\work\\ruby.rb")
> => "ruby.rb"
>

irb(main):001:0> VERSION
=> "1.8.6"
irb(main):002:0> File.basename("C:\\home\\gumby\\work\\ruby.rb")
=> "C:\\home\\gumby\\work\\ruby.rb"
irb(main):003:0>

7stud -- wrote:

irb(main):001:0> VERSION
=> "1.8.6"
irb(main):002:0> File.basename("C:\\home\\gumby\\work\\ruby.rb")
=> "C:\\home\\gumby\\work\\ruby.rb"
irb(main):003:0>
  
So you ran ruby on linux (or OSX) and gave it a fully qualified windows filename, what were you expecting?

Some magical utility that can take a string and work out what operating system the filename comes from and then parse that?

Patches welcome.

7stud -- wrote:

Christopher Dicely wrote:

The documentation is incorrect.

irb(main):049:0> VERSION
=> "1.8.6"
irb(main):050:0> File.basename("C:\\home\\gumby\\work\\ruby.rb") =>
"ruby.rb"

irb(main):001:0> VERSION
=> "1.8.6"
irb(main):002:0> File.basename("C:\\home\\gumby\\work\\ruby.rb") =>
"C:\\home\\gumby\\work\\ruby.rb"
irb(main):003:0>

No it is correct: On a Non-Windows system you can have a file with the
name "C:\\home\\gumby\\work\\ruby.rb" in the actual directory. :stuck_out_tongue:

Regards
Jan

You are faulting File for not being Pathname but the two classes serve two different purposes.

File is primarily an interface to the OS system calls, but with some convenience methods(i.e. basename). Given File you can implement Pathname but given Pathname you can't implement File.

If File doesn't seem OO enough for you that is probably because the underlying Posix interface to filesystems isn't really OO either. That mismatch can be hidden via something like Pathname but at some point a call has to be passed to the OS and its procedural interface, which is pretty much what File presents.

I think this is another example where Ruby tends to be pragmatic rather than pedantic about interfaces. For the simple case of copying the contents of a file to stdout you could write:

fd = File.new(Pathname.new('/etc/motd'))
while part = fd.read(100)
   STDOUT.puts(part)
end
fd.close

or

   STDOUT.puts(Pathname.new('/etc/motd').read)

or just

   puts File.read('/etc/motd')

I know which one I prefer.

Gary Wright

···

On Feb 20, 2008, at 4:29 PM, tom_33 wrote:

Yes, that was indeed the kind of class I was looking for.
Obviously Ruby supports a procedural invocation style of using class
methods on the File class (the same way you would do it with non-oo-
language such as C, i.e. providing the same parameters over and over
again since there is no object that can encapsulate it in a
constructor call).

Path name parsing aside -- which is really a small part of what File does -- here are some comments.

To open and read each line in a file, do this:

File.open(filename, mode) do |f|
   f.each {|line| #do something with the line}
end

Notice that the file is opened and a block yielding the context of the open file is used thereafter for file manipulation. There are a bunch of filesystem interrogation methods that are, by their nature, better handled by passing strings. Why? Because often you don't want to open a file just to find out when it was modified or what its basename is. That's why there are so many class methods (or, if you prefer, "static functions").

Encapsulation is about keeping your data in a safe place where the implementation of the data store is abstracted. Access is through methods that don't change. It's conceivable that you could create a class to wrap the File functions like:

class FileTools
   def initialize(file_name)
     @file_name = file_name
   end

   def basename
     File.basename(@file_name)
   end

   def atime
     File.atime(@file_name)
   end

   # etc.
end

Then you would need to do this in your code:

f = FileTools.new('my.file')
basename = f.basename
last_accessed = f.atime

I don't typically use a ton of these methods, so specifying the string each time isn't a huge burden. Creating a new object just so you can interrogate the filesystem seems like overkill -- it's unlikely the interface to the filesystem will change any time soon.

Just my $.02

···

On Feb 20, 2008, at 1:29 PM, tom_33 wrote:

However, an important difference with ruby File class and the java
File class is that the java class provides a cohesive unit of instance
methods that encapsulates a file path, without having to provide a
string as parameter to every method.

I do believe (as the evidence has shown) that File.basename is OS-specific.

Arlen

···

On Feb 20, 2008 10:33 PM, Thomas Wieczorek <wieczo.yo@googlemail.com> wrote:

I am on Windows XP:

irb(main):001:0> File.basename("C:\\home\\gumby\\work\\ruby.rb")
=> "ruby.rb"
irb(main):002:0> VERSION
=> "1.8.6"

Hi,

···

On Feb 20, 2008 10:54 PM, Peter Hickman <peter@semantico.com> wrote:

So you ran ruby on linux (or OSX) and gave it a fully qualified windows
filename, what were you expecting?

Some magical utility that can take a string and work out what operating
system the filename comes from and then parse that?

Patches welcome.

Taking a quick look at file.c in Ruby's source code, it seems we'd just have
to split the function in two (rather than the define mess we have now), and
then add a short bit to look for the presence of a start like /[a-zA-Z]:\\/,
then use the DOS-like one, otherwise try Unix-like ...

Arlen

No, the documentation is incorrect: it states that the only path
separator accepted by File.basename is "/" regardless of OS. But the
method clearly accepts "\" (properly escaped) on Windows systems.

···

On Feb 20, 2008 4:45 AM, Jan Friedrich <janfri.rubyforge@gmail.com> wrote:

7stud -- wrote:

> Christopher Dicely wrote:
>> The documentation is incorrect.
>>
>> irb(main):049:0> VERSION
>> => "1.8.6"
>> irb(main):050:0> File.basename("C:\\home\\gumby\\work\\ruby.rb") =>
>> "ruby.rb"
>>
>>
>
> irb(main):001:0> VERSION
> => "1.8.6"
> irb(main):002:0> File.basename("C:\\home\\gumby\\work\\ruby.rb") =>
> "C:\\home\\gumby\\work\\ruby.rb"
> irb(main):003:0>

No it is correct: On a Non-Windows system you can have a file with the
name "C:\\home\\gumby\\work\\ruby.rb" in the actual directory. :stuck_out_tongue:

Regards
Jan