tags:

views:

288

answers:

4

Here I have the start of a news posting app I'm working on in ruby. Creating an article works fine, but I'm lost as to how to retrieve one. I'd like my Article.get method to return an article object,.. but it seems the only way to do this is to make all the Article attributes writable, which I don't really want to do. Are there any better ways to go about doing this?

require 'date'
require 'ftools'
require 'find'

module News
    class Article
        attr_reader :topic, :body, :created, :directory, :file_name, :file, :author
        attr_writer :topic, :body, :created, :directory, :file_name, :file, :author

        def initialize(author, topic, body)
            @topic = topic
            @body = body
            @author = author
            @created = DateTime.now()
            @directory = 'archive/' + @created.strftime('%Y/%m') + '/'
            @file_name = @created.strftime('%H-%M-%S')
            @file = @directory + @file_name

            File.makedirs(@directory) unless File.directory?(@directory)

            if !File.file?(@file)
                @article = File.new(@file, 'w', 0777)
                @article.print "#{@topic}\n#{@author}\n#{@body}"
                @article.close()
            end
        end

        def Article.get(path)
        #???
        end
    end
+3  A: 

I think the problem here is that you are using the initialize method to save the record to the filesystem, when if you want to instantiate an article object to return with

Article.new

then that will also call the initialize method; which is probably why it's confusing; you seem to be conflating two things into one method.

So to simplify it, I would have a separate persist (save) method, from your initialize method.

I'm sure you have good reasons for doing this on a file system rather than a database, but I can't help feeling it would be instructive to read about the active record pattern, whether it is the Ruby implementation of it (if you decide to use a database) or just the pattern.

DanSingerman
A: 

Having a seperate save function seems essential to getting this onto the right path.

A: 

I would probably have made two classes, one responsible for reading and writing articles to disk (or databases or whereever), and one for the articles. It would then be easy for the storage-class, say ArticleStorage, to read from the disk and create an Article-instance, which could then be returned.

Something like


class ArticleStorage
  def self.save(article)
    # Make sure the folder is available, and the file is writable
    file.puts(article.to_s)
  end

  def self.load(title)
    # Open the file named title in the right directory
    # Read the file into a hash for example
    return Article.new(file[:author], file[:topic], file[:body], file[:created])
  end
end

class Article
  def initialize(author, topic, body, created)
    # save variables
  end

  def to_s
    # Format and prepare the article for saving
  end
end

Then you could do something like a = Article.new("author", "my topic", "long text", Time.now) and save it with ArticleStorage.save(a) and load with a = ArticleStorage.load("my topic")

A: 

Is there a way I can store the object in @created in the articles text file for retrieval?

This really does beg the question 'why aren't you using a database?'
DanSingerman
`astring_to_be_written = @created.to_s` this string can be stored in a text file. You can construct a time later using: `@created = DateTime.parse(astring_from_file)`. A real database instead of an ad-hoc file-based database could do a better job.
J.F. Sebastian